【问题标题】:Java 8 stream groupingBy. How to set field if only one object of grouping value?Java 8 流分组依据。如果只有一个分组值对象,如何设置字段?
【发布时间】:2019-11-27 08:24:28
【问题描述】:

我有课

public class SomeClass {

    private String date;
    private int players;
    private int currency;

// getters setters omitted for brevity
}

我收集了这些物品。现在我想按日期对这些对象进行分组并对玩家计数进行汇总并将currencyId 设置为0。我这样做是这样的:

list = list.stream()
           .collect(
                    groupingBy(SomeClass::getDate,
                              collectingAndThen(reducing((a, b) -> {
                                  a.setDate(a.getDate());
                                  a.setPlayers(a.getPlayers() + b.getPlayers());
                                  a.setCurrency(0);
                                  return a;
                              }), Optional::get)))
           .values();

一切都很好,除非我只有一个特定日期的对象。该对象没有将货币设置为 0(因为如果对象只有一个,则减少不起作用。)所以这是我的问题。

如果我有:

   Object1 ("11.09", 12, 12)
   Object2 ("11.09", 8, 13)
   Object3 ("12.09", 1, 2)
   Object4 ("12.09", 0, 1)
   Object5 ("13.09", 12, 12)

输出必须是:

   Object6 ("11.09", 20, 0)
   Object7 ("12.09", 1, 0)
   Object8 ("13.09", 12, **0**)

但是:

   Object6 ("11.09", 20, 0)
   Object7 ("12.09", 1, 0)
   Object8 ("13.09", 12, **12**)

请帮忙

【问题讨论】:

  • 你真的关心那个字段值吗?你需要对象实例吗?你不想得到一个Map<String, Integer> 每天的玩家人数吗?
  • a.setDate(a.getDate()) 幸好没有操作。如果您实际上更改了 reducer 内部的分组键,那可能会破坏您的地图。
  • Reduction 不是用于操作源对象的工具。除此之外,收集器模式groupingBy(f1, collectingAndThen(reducing(f2), Optional::get) 可以简化为toMap(f1, Function.identity(), f2)
  • @AntonKolosok 你的意思是,除了是一半的代码并且不需要运行结果映射来调用每个组上的Optional::get 吗?
  • 没有其他区别。两个收集器都会生成一张地图,而且通常两者都可用于生成相同的结果,但根据用例,一个可能比另一个更适合。另见this Q&A

标签: java java-8 stream java-stream


【解决方案1】:

货币未设置为 0,因为 reducing 不会针对单个结果进行评估。如果要将所有货币设置为 0,请将其映射为 0,如下所示,

list.stream().map(ele->{ele.setCurrency(0);return ele;}).collect(
        groupingBy(SomeClass::getDate,
                collectingAndThen(reducing((a, b) -> {
                    a.setPlayers(a.getPlayers() + b.getPlayers());
                    return a;
                }), Optional::get)))
        .values();

正如@Holger 正确指出的那样,您可能想要使用toMap

list.stream()
    .map(ele->{ele.setCurrency(0);return ele;})
    .collect(toMap(SomeClass::getDate, Function.identity(), (a, b) -> {
        a.setPlayers(a.getPlayers() + b.getPlayers());
        return a;
    })).values();

希望对你有帮助。

【讨论】:

  • 谢谢分配。按预期工作。使用 toMap 而不是 groupBy 有什么好处?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 2012-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多