Java流分组并求和多个字段

新手上路,请多包涵

我有一个列表 fooList

 class Foo {
    private String category;
    private int amount;
    private int price;

    ... constructor, getters & setters
}

我想按类别分组,然后合计金额和价格。

结果将存储在地图中:

 Map<Foo, List<Foo>> map = new HashMap<>();

关键是 Foo 保存汇总的数量和价格,具有相同类别的所有对象的列表作为值。

到目前为止,我已经尝试了以下内容:

 Map<String, List<Foo>> map = fooList.stream().collect(groupingBy(Foo::getCategory()));

现在我只需要用保存汇总金额和价格的 Foo 对象替换 String 键。这就是我被困的地方。我似乎找不到任何方法来做到这一点。

原文由 MatMat 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 776
2 个回答

有点难看,但它应该工作:

 list.stream().collect(Collectors.groupingBy(Foo::getCategory))
    .entrySet().stream()
    .collect(Collectors.toMap(x -> {
        int sumAmount = x.getValue().stream().mapToInt(Foo::getAmount).sum();
        int sumPrice= x.getValue().stream().mapToInt(Foo::getPrice).sum();
        return new Foo(x.getKey(), sumAmount, sumPrice);
    }, Map.Entry::getValue));

原文由 Sweeper 发布,翻译遵循 CC BY-SA 4.0 许可协议

我对 Sweeper 答案 的变体使用减少收集器而不是流式传输两次来对各个字段求和:

 Map<Foo, List<Foo>> map = fooList.stream()
    .collect(Collectors.groupingBy(Foo::getCategory))
    .entrySet().stream()
    .collect(Collectors.toMap(e -> e.getValue().stream()
        .collect(Collectors.reducing(
            (l, r) -> new Foo(l.getCategory(), l.getAmount() + r.getAmount(), l.getPrice() + r.getPrice())))
         .get(), e -> e.getValue()));

不过,它并不是真的 _更好_,因为它会产生很多短暂的 Foos

Note however that Foo is required to provide hashCode - and equals -implementations that take only category into account for the resulting map 正常工作。通常,这可能不是您想要的 Foo 。我宁愿定义一个单独的 FooSummary 类来包含聚合数据。

原文由 Hulk 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题