[英]Java 8: AveragingDouble and mapping to object
我有交易 object 的列表,如下所示:
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:
class Transaction {
private final Trader trader;
private final int year;
private final int value;
private String type;
private String method;
}
现在我需要根据每个组的事务类型找到平均值,最后将平均值转储到Result
object 中,其中包含一些关于正在计算其平均值的组的附加数据等。
在计算之前。 对列表执行以下操作:
并且最终生产的object应该有平均值,年份和方法的价值。
结果 Class:
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()
产生一个双精度值,并且所有其他信息都在此映射中丢失。
有什么方法可以获取这些字段或正确地将 map 结果转换为 object?
你可以这样做:
在使用mapping
收集器按年份和方法分组后,创建Result
object 作为Collectors.mapping(t->new Result(...),)
,正如您所知, mapping
收集器将collector
作为第二个参数。 因为要在分组后合并它们并计算平均值,所以collectingAndThen
器是在这里执行它的最佳选择。 确实 collectAndThen 在collectingAndThen
到列表后将 function 作为整理器(平均函数)并计算列表中所有元素的平均值。
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 的平均值为:
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())))
));
output:
{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']}}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.