【问题标题】:Stream collectingAndThen get latest record to sum a value流收集然后获取最新记录以求和一个值
【发布时间】:2021-01-15 14:32:50
【问题描述】:

目前,我正面临以下数据集。我的目标是通过前两列获得 Column4 组的最新总和。

// Column5 = version
new Foo(1, "bbb", "cccc", 111, 0)
new Foo(1, "bbb", "cccc", 234, 1) // latest
new Foo(1, "bbb", "dddd", 111, 0)
new Foo(1, "bbb", "dddd", 112, 1)
new Foo(1, "bbb", "dddd", 113, 2)
new Foo(1, "bbb", "dddd", 114, 3) // latest
new Foo(1, "xxx", "cccc", 111, 0) // latest
new Foo(2, "xxx", "yyyy", 0, 0)
new Foo(2, "xxx", "yyyy", 1, 1)   // latest
...

我试过的是

// key: Column1, key: Column2, value: latest sum of Column4
Map<Long, Map<String, Integer>> fooMap = fooList.stream().collect(
    Collectors.groupingBy(Foo::getColumn1, Collectors.groupingBy(Foo::getColumn2,
            Collectors.collectingAndThen(????))));

???? 部分我是否尝试过Collectors.groupingByCollectors.maxByCollectors.summingInt

但它总是错的。 ????

我的理想地图应该是这样的:

1-&gt;bbb-&gt;348,1-&gt;xxx-&gt;111,2-&gt;xxx-&gt;1.

请帮忙????让我知道是否需要任何补品。谢谢。

【问题讨论】:

  • 您是如何选择(1, "bbb", "dddd", 114, 3)(1, "bbb", "cccc", 234, 1) 的,两者都是最新的?第三列在分组下也很重要?
  • @Naman 是的。我想按列 1 + 2 + 3 从最新记录 (Column5) 组中获取 Column4 的总和。

标签: java java-8 java-stream groupingby


【解决方案1】:

您可以通过以下方式获得它:

    Map<Long, Map<String, Integer>> fooMap = fooList.stream().collect(
            groupingBy(Foo::getColumn1,
                    groupingBy(Foo::getColumn2,
                            collectingAndThen(
                                    groupingBy(Foo::getColumn3,
                                            collectingAndThen(
                                                    maxBy(comparing(Foo::getVersion)),
                                                    Optional::get
                                            )),
                                    m -> m.values().stream().mapToInt(Foo::getColumn4).sum()
                            )
                    )
            ));

首先按 column1 和 column2 分组,然后我们使用 collectingAndThen 进行按 column3 分组,因为我们要对其进行后期处理。

按 column3 分组,我们想要按版本获取最大值,我们使用另一个 collectingAndThen,因为 maxBy 创建和 Optional,所以我们应用 Optional::Get 来获得 Map&lt;String, Foo&gt; 而不是 Map&lt;String, Optional&lt;Foo&gt;&gt;

post 过程是对地图中 Foo 的所有 column4 求和,即版本最大的那些。

【讨论】:

  • 感谢您的回复。但我只想按列 1 + 2 + 3 从最新记录(Column5)组中获取 Column4 的总和。例如1-&gt;bbb-&gt;348 ,来自数据集的 234 + 114。
  • 对不起,我误解了你的问题。我更新了答案
  • 应该是我一开始就想要拥有的?
【解决方案2】:

将模型表示为:

record Foo(Long one, String two, String three, int value, int version) {
}

record Result(Long one, String two, int totalValue) {
}

您可以从按前三个属性分组并将值映射到选择最大版本的标识开始。

Map<List<Object>, Foo> groupedMaxVersion = fooList.stream()
        .collect(Collectors.toMap(foo -> Arrays.asList(foo.one(), foo.two(), foo.three()),
                foo -> foo, BinaryOperator.maxBy(Comparator.comparing(Foo::version))));

这之后可以根据第 4 列中的值对下游求和:

Map<List<Object>, Integer> resultMapping = groupedMaxVersion.entrySet().stream()
        .collect(Collectors.groupingBy(e -> Arrays.asList(e.getKey().get(0), e.getKey().get(1)),
                Collectors.summingInt(e -> e.getValue().value())));

此外,您只需根据需要将其框架到结果数据结构中

resultMapping.entrySet().stream()
                .map(e -> new Result((Long) e.getKey().get(0), (String) e.getKey().get(1), e.getValue()))
                .collect(Collectors.toList()); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2022-11-14
    • 2018-08-13
    • 2017-02-19
    • 1970-01-01
    相关资源
    最近更新 更多