【问题标题】:java streams: straightforward reducejava流:直接减少
【发布时间】:2019-01-08 10:34:20
【问题描述】:

我有一个MetricGroup 流,其中:

public class MetricGroup {

    private int uploadedDocs;
    private long uploadedKbs;

    // getters and setters

}

我需要将所有指标汇总到一个指标中。我的意思是,我需要将所有metric.uploadedDocs 添加到sumMetric.uploadedDocsmetric.uploadedKdssumMetric.uploadedKbs

我发现我需要某种reduce

Stream.of(new MetricGroup(1,100), new MetricGroup(1,200))
    .reduce(????);

有什么想法吗?

【问题讨论】:

  • 您要编辑现有的还是需要为结果创建一个新的 MetricGroup?
  • 恕我直言,使用两个简单的reduce/sum而不是一个过于复杂的reduce/sum会更简单、更容易理解和维护。
  • @tobias_k 确实好喊!,我在阅读本文时也有类似的想法(在下面发布了答案)。希望你没事:)
  • 请考虑接受答案。或者您还有什么想问的吗?

标签: java java-8 java-stream


【解决方案1】:

你可以使用reduce这个重载:

T reduce(T identity,
     BinaryOperator<T> accumulator)

像这样:

.reduce(new MetricGroup(0, 0),
        (x, y) -> new MetricGroup(
                      x.getUploadedDocs() + y.getUploadedDocs()
                      x.getUploadedKbs() + y.getUploadedKbs()
                  )
        )

您也可以使用collect 方法:

private static MetricGroup combine(MetricGroup x, MetricGroup y) {
    x.setUploadedDocs(x.getUploadedDocs() + y.getUploadedDocs());
    x.setUploadedKbs(x.getUploadedKbs() + y.getUploadedKbs());
    return x;
}

// ....

.collect(() -> new MetricGroup(0, 0),
    YourClass::combine,
    YourClass::combine
)

【讨论】:

  • 我认为这是最好的解决方案,因为它不会操纵现有的 MetricGroups
  • @FedericoPeraltaSchaffner 你是对的。我在想collect
【解决方案2】:

为避免在reduce 调用期间创建多个/多个MetricGroup 对象,您可以进行两次单独调用以分别对UploadedDocsUploadedKbs 求和,然后构造一个新的MetricGroup 表示结果.

int uploadedDocsSum = source.stream().mapToInt(MetricGroup::getUploadedDocs).sum();
long uploadedKbsSum = source.stream().mapToLong(MetricGroup::getUploadedKbs).sum();
MetricGroup result = new MetricGroup(uploadedDocsSum, uploadedKbsSum);

可以说也更具可读性...

【讨论】:

  • 在最坏的情况下,它只是用其他方法创建的一个对象。此外,您有两个流,而其他解决方案与一个流一起使用。但你的可能更具可读性。
  • 恕我直言,这种方法的唯一问题可能是,如果 OP 确实只有一个流实例的引用,并且它太大而无法在列表中缓冲。
  • @tobias_k 我的错,我正在处理我的 IDE 上的另一个问题,却忘了在这里解决它。现已编辑。
  • @user489872 另一方面,其他方法有 2*n 次对 getter 的调用和另外 n 次对 setter 的调用,而这只对 getter 进行了 n 次调用。
【解决方案3】:

只需传入一个 lambda(将操纵现有的 MetricGroup)

Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
    .reduce((a, b) -> {
      a.setUploadedDocs(a.getUploadedDocs() + b.getUploadedDocs());
      a.setUploadedKbs(a.getUploadedKbs() + b.getUploadedKbs());
      return a;
    });

// Optional[F.MetricGroup(uploadedDocs=2, uploadedKbs=300)]

或者,真正获得一个新的 MetricGroup(不操纵现有的)

Stream.of(new MetricGroup(1, 100), new MetricGroup(1, 200))
        .reduce((a, b) -> new MetricGroup(a.getUploadedDocs() + b.getUploadedDocs(), a.getUploadedKbs() + b.getUploadedKbs()));

【讨论】:

    【解决方案4】:

    与 Java 流一样,您实际上不必使用它们。我建议创建一个简单的归约辅助方法:

    public static MetricGroup reduce(Iterable<? extends MetricGroup> metrics){
       int uploadedDocs = 0;
       long uploadedKbs = 0L;
       for(MetricGroup metric : metrics){
           uploadedDocs += metric.getUploadedDocs();
           uploadedKbs += metric.getUploadedKbs();
       }
       return new MetricGroup(uploadedDocs, uploadedKbs);
    }
    

    如果您无法更改从流开始的情况,您仍然可以使用上述方法,只需传递对 Stream.iterator() 方法的引用即可:

    MetricGroup reduced = reduce(stream::iterator);
    

    【讨论】:

      【解决方案5】:

      如果您想使用归约,我建议将 MetricGroup 设为值类型,方法是将字段设为 final,添加零,并用组合方法替换 setter。

      public class MetricGroup {
          private final int uploadedDocs;
          private final long uploadedKbs;
      
          // obvious constructor
          // getters
      
          public static final ZERO = new MetricGroup(0, 0);
      
          public MetricGroup add(MetricGroup a, MetricGroup b) {
              return new MetricGroup(a.uploadedDocs + b.upLoadedDocs,
                                     a.uploadedKbs + b.uploadedKbs);
          }
      
          public MetricGroup uploadOneDoc(long kbs) {
              return new MetricGroup(uploadedDocs + 1, uploadedKbs + kbs);
          }
      }
      

      这会让你很好地执行流操作:

      MetricGroup sum = metricGroups.stream()
                                    .reduce(MetricGroup.ZERO, MetricGroup::add);
      

      【讨论】:

      • 好答案,我真的很喜欢常量ZERO 度量组
      猜你喜欢
      • 2019-02-09
      • 2015-11-05
      • 2019-03-08
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 2020-05-04
      • 2017-10-28
      • 1970-01-01
      相关资源
      最近更新 更多