首页 > 解决方案 > 如何使用 Java 8 进行分组和收集?

问题描述

我有一个元素列表,我们称之为“关键字”,如下所示:

public class Keyword {
    Long id;
    String name;
    String owner;
    Date createdTime;
    Double price;
    Date metricDay;
    Long position;
}

问题是每一天都有一个关键字。例如:

Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.1", metricDay="11/11/1999", position=109}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.3", metricDay="12/11/1999", position=108}
Keyword{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", price="0.2", metricDay="13/11/1999", position=99}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.6", metricDay="13/11/1999", position=5}
Keyword{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="14/11/1999", position=4}
Keyword{id=3, name="kw3", owner="Josh", createdTime="13/12/1992", price="0.1", metricDay="13/11/1999", position=8}

然后,从这个列表中,我想创建一个新列表,其中包含所有不同日子的所有指标在一个列表中。首先,我创建了一个这样的类:

public class KeywordMetric {
    Double price;
    Date metricDay;
    Long position;
} 

我想要归档的是从第一个列表到这样的结构:

public class KeywordMeged {
    Long id;
    String name;
    String owner;
    List<KeywordMetric> metricList;
}

我期望的例子:

KeywordMerged{id=1, name="kw1", owner="Josh", createdTime="12/12/1992", metricList=[KeywordMetric{price=0.1,metricDay="11/11/1999",position=109},KeywordMetric{price=0.3,metricDay="12/11/1999",position=108},KeywordMetric{price=0.2,metricDay="13/11/1999",position=99}]
KeywordMerged{id=2, name="kw2", owner="Josh", createdTime="13/12/1992", metricList=[KeywordMetric{price=0.6,metricDay="13/11/1999",position=5},KeywordMetric{price=0.1,metricDay="14/11/1999",position=4}]
KeywordMerged{id=3, name="kw3", owner="Josh", createdTime="13/12/1992", metricList=[KeywordMetric{price=0.1,metricDay="13/11/1999",position=8}]

我知道如何使用大量循环和可变变量来做到这一点,但我无法弄清楚如何使用流和 lambda 操作来做到这一点。我可以按 ID 对所有相关关键字进行分组:

Map<Long, List<Keyword>> kwL = kwList.stream()
                    .collect(groupingBy(Keyword::getId))

而且我知道.forEach()我可以迭代该 Map,但无法弄清楚如何使collect()流的方法从 List 传递到 KeywordMerged。

标签: javajava-8java-stream

解决方案


略有不同的方法。首先,您收集按 id 分组的关键字 Map:

Map<Integer, List<Keyword>> groupedData = keywords.stream()
    .collect(Collectors.groupingBy(k -> k.getId()));

此外,您将地图转换为所需格式的列表:

List<KeywordMerged> finalData = groupedData.entrySet().stream()
    .map(k -> new KeywordMerged(k.getValue().get(0).getId(),
        k.getValue().stream()
            .map(v -> new KeywordMetric(v.getMetricDay(), v.getPrice(), getPosition()))
            .collect(Collectors.toList())))
    .collect(Collectors.toList());

这将适用于分组数据,但转换地图将创建KeywordMerged对象,该对象作为参数将接收 id(您可以自己进一步扩展)并转换为List<KeywordMetric>先前按 ID 分组的数据。

编辑:我相信通过一些提取方法可以使它看起来更好:)


推荐阅读