简体   繁体   English

Java 8:平均双并映射到 object

[英]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:对列表执行以下操作:

  • grouping the transaction with year将交易与年份分组
  • then grouping by method然后按方法分组

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM