【问题标题】:Java 8: AveragingDouble and mapping to objectJava 8:AveragingDouble 和映射到对象
【发布时间】:2020-05-05 20:11:00
【问题描述】:

我有如下所示的交易对象列表:

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 对象中,其中包含一些关于正在计算其平均值的组的额外数据等。

在计算之前。对列表执行以下操作:

  • 按年份分组交易
  • 然后按方法分组

最终生成的对象应该有平均值、年份和方法的值。

结果类:

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() 会生成一个双精度值,并且此映射中会丢失所有其他信息。

有什么方法可以获取这些字段或将结果正确映射到对象中?

【问题讨论】:

    标签: java lambda java-8 java-stream collectors


    【解决方案1】:

    你可以这样做:

    yearmethodmappingcollector 分组后创建Result 对象为Collectors.mapping(t-&gt;new Result(...),),如您所知mappingcollector 采用collector作为第二个论点。因为要在分组后合并它们并计算平均值,collectingAndThencollector 是这里执行的最佳选择。确实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());
    

    【讨论】:

      【解决方案2】:

      您可以使用averagingDouble 收集到Map&lt;Integer, Map&lt;String, Double&gt;&gt;,就像在 OP 中一样:

      Map<Integer, Map<String, Double>> doubleMap = transactions.stream()
                      .collect(groupingBy(Transaction::getYear,
                              groupingBy(Transaction::getMethod,
                                      averagingDouble(Transaction::getValue))));
      

      然后重新映射到Map&lt;Integer, Map&lt;String, Result&gt;&gt;

      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']}}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        • 2016-06-01
        • 2018-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-18
        相关资源
        最近更新 更多