【问题标题】:java streams: grouping by and add fieldsjava流:分组和添加字段
【发布时间】:2019-01-08 10:58:44
【问题描述】:

我有一个MetricGroup 流,其中:

public class MetricGroup {

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

    // getters and setters

}

我需要汇总所有应用程序指标。我的意思是,对于每个应用程序 (MetricGroup.application),我需要将所有 metric.uploadedDocs 添加到 sumMetric.uploadedDocsmetric.uploadedKdssumMetric.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) >

有什么想法吗?

【问题讨论】:

  • 您在similar question asked 30 mins ago 上得到的答案有什么问题?
  • 我需要按应用程序分组,在另一篇文章中我只需要总结所有对象。现在我需要按应用进行总结。

标签: java java-8 java-stream grouping


【解决方案1】:

您可以按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());     

【讨论】:

    【解决方案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 元素。

    【讨论】:

      【解决方案3】:

      你可以试试这样的

      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();
      

      【讨论】:

        【解决方案4】:

        MetricGroup.application分组时使用Collectors.reducing

        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()))));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-02-03
          • 1970-01-01
          • 2013-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多