首页 > 解决方案 > Java 8:AveragingDouble 和映射到对象

问题描述

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

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

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

标签: javalambdajava-8java-streamcollectors

解决方案


你可以这样做:

在按年份方法mapping收集器创建Result对象 as进行分组后Collectors.mapping(t->new Result(...),),您知道mapping收集器将 acollector作为第二个参数。因为你想在分组后合并它们并计算平均值,所以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());

推荐阅读