我有如下所示的事务对象列表。
List<Transaction> transactions = Arrays.asList(
new Transaction(brian, 2011, 300, "X", "M1"),
new Transaction(raoul, 2012, 1000, "T", "M1"),
new Transaction(raoul, 2011, 400, "S", "M2"),
new Transaction(mario, 2012, 710, "X", "M1"),
new Transaction(mario, 2012, 700, "X", "M2"),
new Transaction(alan, 2012, 950, "T", "M1")
);
事务类 。
class Transaction {
private final Trader trader;
private final int year;
private final int value;
private String type;
private String method;
}
现在我需要根据每组的事务类型找到平均值,最后将平均值转储到一个 Result
对象,并附加一些关于正在计算AVG的组的数据等。
在计算之前,对列表进行以下操作。
而最后产生的对象应该有平均数、年份和方法的值。
结果类。
class Result {
private Double avg;
private int year;
private String method;
}
代码。
Map<Integer, Map<String, Result>> res = transactions.stream().collect(
groupingBy(Transaction::getYear,
groupingBy(Transaction::getMethod),
collectingAndThen( averagingDouble( t -> "X".equals(t.getType()) ? 1: 0 ),
v -> new Result(v, GROUP_METHOD? , GROUP_YEAR?))
)
);
但是GROUP_METHOD &GROUP_YEAR的值在这里是无法访问的, 因为在这里是根据分组来进行的 averagingDouble()
产生了一个双倍的结果,而所有其他信息都在这个映射中丢失了。
有什么办法可以抓住这些字段或将结果正确地映射到一个对象中吗?
你可以这样做。
在按以下方式分组之后 年 和 办法 与 mapping
采集器 Result
对象 Collectors.mapping(t->new Result(...),)
你知道的 mapping
采集器 collector
作为第二个参数。因为你想在分组后将它们合并,计算平均值。collectingAndThen
采集器是在这里执行的最佳选择。collectingAndThen
收集到列表后,以一个函数作为终点(平均函数),计算列表中所有元素的平均值。
transactions.stream().collect(
groupingBy(Transaction::getYear,
groupingBy(Transaction::getMethod,
mapping(t -> new Result((double) t.getValue(), t.getYear(), t.getMethod()),
collectingAndThen(Collectors.toList(), average::apply)))));
而平均函数就是。
Function<List<Result>, Result> average = l -> new Result(l.stream()
.mapToDouble(Result::getAvg)
.average().orElse(0d), l.get(0).getYear(), l.get(0).getMethod());
你可以用 averagingDouble
收至 Map<Integer, Map<String, Double>>
和OP一样。
Map<Integer, Map<String, Double>> doubleMap = transactions.stream()
.collect(groupingBy(Transaction::getYear,
groupingBy(Transaction::getMethod,
averagingDouble(Transaction::getValue))));
那就重映射到 Map<Integer, Map<String, Result>>
:
Map<Integer, Map<String, Result>> resultMap = doubleMap.entrySet().stream()
.flatMap(my -> my.getValue().entrySet().stream()
.map(mm -> new Result(mm.getValue(), my.getKey(), mm.getKey())))
.collect(groupingBy(Result::getYear, toMap(Result::getMethod, Function.identity())));
或在单一声明中使用 collectingAndThen
:
Map<Integer, Map<String, Result>> collect1 = transactions.stream()
.collect(collectingAndThen(
groupingBy(Transaction::getYear,
groupingBy(Transaction::getMethod,averagingDouble(Transaction::getValue))),
map -> map.entrySet().stream()
.flatMap(my -> my.getValue().entrySet().stream()
.map(mm -> new Result(mm.getValue(), my.getKey(), mm.getKey())))
.collect(groupingBy(Result::getYear,
toMap(Result::getMethod, Function.identity())))
));
产出:
{2011={M1=Result[avg=300.0, year=2011, method='M1'], M2=Result[avg=400.0, year=2011, method='M2']},
2012={M1=Result[avg=886.6666666666666, year=2012, method='M1'], M2=Result[avg=700.0, year=2012, method='M2']}}