计算地图中列表的总和



我有一个交易列表,它是按地区和状态分组的地图。交易类有一个属性金额字段。

Map<Region, Map<Status, List<Trade>>> groupedTrades
class Trade {
double amount;
}

我想在列表中对不同交易的金额进行分组,并将其返回为以下

Map<Region, Map<Status, Double>> sumOfGroupedTradeAmounts

Double是交易列表中所有金额字段的总和。

我如何在java8中做到这一点?

您可以这样做。基本上,你是:

  • 执行entrySets的嵌套流
  • 流式传输外部映射条目以获得内部映射值和外部映射键
  • 在内部条目集中,对值(即List<Doubles>(进行流式传输,并对其求和
  • 然后使用外部映射键、内部映射键和贸易金额的总和在指定的映射中返回这些值,得到一个双值

注意,我为amount检索向Trade类添加了一个getter。

class Trade {
double amount;

public double getAmount() {
return amount;
}
}

public static void main(String[] args) {
Map<Region, Map<Status, Double>> result = groupedTrades
.entrySet().stream()
// outer map starts here, keying on Region
.collect(Collectors.toMap(Entry::getKey, e -> e
.getValue().entrySet().stream()
// inner map starts here, keying on Status
.collect(Collectors.toMap(Entry::getKey,
// stream the list and sum the amounts.
ee -> ee.getValue().stream()
.mapToDouble(Trade::getAmount)
.sum()))));

}

给定以下结构,其中RegionStatus分别是numbersletters

Map<Region, Map<Status, List<Trade>>> groupedTrades = Map.of(   
new Region(1),                                          
Map.of(new Status("A"),                                 
List.of(new Trade(10), new Trade(20),           
new Trade(30)),                         
new Status("B"),                                
List.of(new Trade(1), new Trade(2))),           
new Region(2),                                          
Map.of(new Status("A"),                                 
List.of(new Trade(2), new Trade(4),             
new Trade(6)),                          
new Status("B"), List.of(new Trade(3),          
new Trade(6), new Trade(9))));
result.forEach((k, v) -> {                           
System.out.println(k);                           
v.forEach((kk, vv) -> System.out                 
.println("     " + kk + " -> " + vv));   
});                                                            

这是示例输出。

2
B -> 18.0
A -> 12.0
1
B -> 3.0
A -> 60.0

如果您有兴趣求和值的all。通过使用刚刚创建的doubles嵌套映射,您可以按如下方式进行操作。

double allSums =
// Stream the inner maps 
result.values().stream()
// put all the Doubles in a single stream
.flatMap(m->m.values().stream())
// unbox the Doubles to primitive doubles
.mapToDouble(Double::doubleValue)
// and sum them
.sum();

仅使用流,它可能看起来如下:

Map<Region, Map<Status, Double>> result =
groupedTrades
.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey, // Leave key as is
entry -> mapToDouble(entry.getValue(), MyClass::sumOfTrades))); // applies sumOfTrades (See below)

为了保持流的可读性,我们定义了小助手函数:

// Takes map which contains lists of trades and and applies function mapper, which returns T (might be double) on those lists
private static <T> Map<Status, T> mapToDouble(Map<Status, List<Trade>> trades, Function<List<Trade>, T> mapper) {
return trades.entrySet()
.stream()
.collect(Collectors.toMap(
Map.Entry::getKey, // Leave key as is
entry -> mapper.apply(entry.getValue())));
}
// Takes a list of trades and returns its sum
private static double sumOfTrades(List<Trade> trades) {
return trades.stream().mapToDouble(Trade::getAmount).sum();
}

奖金-所有交易的总和:

double sum =
groupedTrades
// get collection of "inner" maps
.values()
.stream()
// get only their values as collection of lists 
.map(Map::values)
// map the collection into stream of lists
.flatMap(Collection::stream)
// map the collection stream of lists into stream of Trade values
.flatMap(Collection::stream)
// map Trade into double value - "amount"
.mapToDouble(Trade::getAmount)
// get the sum
.sum();

最新更新