[英]Java 8: AveragingDouble and mapping to object
I have list of transaction object as shown below:我有交易 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")
);
Transaction Class:事务 Class:
class Transaction {
private final Trader trader;
private final int year;
private final int value;
private String type;
private String method;
}
Now I need to find the average based on type of transaction per group and finally dump the average into a Result
object with some additional data about group whose avg is being computed etc.现在我需要根据每个组的事务类型找到平均值,最后将平均值转储到
Result
object 中,其中包含一些关于正在计算其平均值的组的附加数据等。
prior to computing.在计算之前。 following operation are performed on the list:
对列表执行以下操作:
and the final object produced should have average, year and method's value in it.并且最终生产的object应该有平均值,年份和方法的价值。
Result Class:结果 Class:
class Result {
private Double avg;
private int year;
private String method;
}
Code:代码:
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?))
)
);
But the GROUP_METHOD & GROUP_YEAR values are not accessible here based on which grouping is done since averagingDouble()
produces a double and all other information is lost in this mapping.但是 GROUP_METHOD 和 GROUP_YEAR 值在此处无法根据分组进行访问,因为
averagingDouble()
产生一个双精度值,并且所有其他信息都在此映射中丢失。
is there any way we can grab these fields or to properly map the result into a object?有什么方法可以获取这些字段或正确地将 map 结果转换为 object?
You can do this:你可以这样做:
After grouping by year and method with mapping
collector create Result
object as Collectors.mapping(t->new Result(...),)
, as you know mapping
collector takes a collector
as a second argument.在使用
mapping
收集器按年份和方法分组后,创建Result
object 作为Collectors.mapping(t->new Result(...),)
,正如您所知, mapping
收集器将collector
作为第二个参数。 Because you want to merge them after grouping and calculate the average, collectingAndThen
collector is the best choice to perform it here.因为要在分组后合并它们并计算平均值,所以
collectingAndThen
器是在这里执行它的最佳选择。 indeed collectingAndThen
after collecting to list takes a function as a finisher(average function) and calculates average value for all elements in the list.确实 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)))));
and the average function is: 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());
You could use averagingDouble
to collect to a Map<Integer, Map<String, Double>>
as in OP:您可以使用
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))));
Then remap to Map<Integer, Map<String, Result>>
:然后重新映射到
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())));
or in a single statement using collectingAndThen
:或在使用
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: 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.