Java流:按分组并添加字段

时间:2019-01-08 10:58:45

标签: java java-8 java-stream grouping

我有MetricGroup的信息流,其中:

public class MetricGroup {

    private String application;
    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

我需要总结所有应用程序指标。我的意思是,对于每个应用程序(MetricGroup.application,我需要将所有metric.uploadedDocs添加到sumMetric.uploadedDocs中,并将metric.uploadedKds添加到sumMetric.uploadedKbs中。

我发现我需要某种groupingBy

Stream.of(
    new MetricGroup("app1", 1,100),
    new MetricGroup("app1", 1,300),
    new MetricGroup("app2", 1,200)
)
.collect(Collector.groupingBy(MetricGroup::getApplication, accumulator??, combiner??)

结果将是具有以下内容的流:

< MetricGroup("app1", 2, 400) , MetricGroup("app2", 1, 200) >

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

您可以按application分组,然后将结果映射到MetricGroup

source.stream()
      .collect(groupingBy(MetricGroup::getApplication))
      .entrySet().stream()
      .map(s -> new MetricGroup(s.getKey(), 
                 s.getValue().stream().mapToInt(MetricGroup::getUploadedDocs).sum(),
                 s.getValue().stream().mapToLong(MetricGroup::getUploadedKbs).sum()))
      .collect(Collectors.toList());     

答案 1 :(得分:2)

如果可以将以下复制构造函数和merge方法添加到MetricGroup类中:

public MetricGroup(MetricGroup another) {
    this.application = another.application;
    this.uploadedDocs = another.uploadedDocs;
    this.uploadedKbs = another.uploadedKbs;
}

public MetricGroup merge(MetricGroup another) {
    this.uploadedDocs += another.uploadedDocs;
    this.uploadedKbs += another.uploadedKbs;
    return this;
}

然后,您可以使用Collectors.toMap按应用程序对指标进行分组:

Map<String, MetricGroup> result = Stream.of(
        new MetricGroup("app1", 1,100), 
        new MetricGroup("app1", 1,300), 
        new MetricGroup("app2", 1,200))
.collect(Collectors.toMap(
        MetricGroup::getApplication, 
        MetricGroup::new,      // use copy constructor
        MetricGroup::merge));  // use MetricGroup.merge method

请注意,我们需要使用复制构造函数来不使流的原始MetricGroup元素发生变异。

答案 2 :(得分:1)

您可以尝试类似的事情

private static final List<MetricGroup> mgArr = Arrays.asList(new MetricGroup("app1", 1,100),new MetricGroup("app1", 1,300),new MetricGroup("app2", 1,200));

Map<String, Long> groupedByAppKbs = mgArr.stream()
                .collect(groupingBy(MetricGroup::getApplication, summingLong(MetricGroup::getUploadedKbs)));

比访问变量更重要:

groupedByAppKbs.get("app1").longValue();

答案 3 :(得分:1)

在按Collectors.reducing分组时使用MetricGroup.application

Map<String, MetricGroup> collect = 
      source.stream()
            .collect(
                   groupingBy(MetricGroup::getApplication,
                              reducing(new MetricGroup(null, 0, 0),
                                       (m1, m2) -> new MetricGroup(
                                               m2.application,
                                               m1.getUploadedDocs() + m2.getUploadedDocs(),
                                               m1.getUploadedKbs() + m2.getUploadedKbs()))));