使用独特的组合器和累加器进行流减少的示例

Eug*_*aci 8 java java-stream

问题是关于java.util.stream.Stream.reduce(U identity,BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)方法。

要求之一是组合器功能必须与累加器功能兼容。对于所有u和t,必须满足以下条件:

 combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t) (*) 
Run Code Online (Sandbox Code Playgroud)

如果combiner和accumulator相同,则上述相等性自动成立。

我的问题

有没有使用combiner和和减少流的示例accumulator?

更新

为了澄清一些事情:

BinaryOperator实际上是在扩展BiFunction,因此在需要BiFunction时可以使用它。如果U和T相同,则始终是合法的:

operator<T> op = (x,y) -> something;

stream.reduce(id, op, op);
Run Code Online (Sandbox Code Playgroud)

我从来没有说过我可以一直使用combineras,acumulator因为在一般情况下,它们用于不同的目的并且是不同的Java类型。


另外,我对平凡的示例不感兴趣,但对并行流进行归约时在实践中遇到的自然示例不感兴趣。

对于一些琐碎的示例,有很多教程,例如本教程


我为什么要问这个问题

基本上,存在这种简化方法的原因是针对并行流。在我看来,条件(*)如此之强,以至于在实践中,由于很少有还原操作可以实现此还原,因此它使还原无效。

use*_*601 0

所以,这里有几个例子。其中一些可能被认为是“微不足道的”,特别是当已经有一个函数可以为您做这件事的时候。

T和U相同的示例

这些很难想出,而且有点做作,因为它们通常涉及假设流的元素和正在累积的对象具有不同的含义,即使它们具有相同的类型。

数数

如果我们有一个整数流,我们可以使用以下方法对它们进行计数reduce:

stream.reduce(0, (count, item) -> count+1, (a, b) -> a+b);
Run Code Online (Sandbox Code Playgroud)

显然,我们可以stream.count()在这里使用,但我愿意打赌内部count使用 3 个参数版本reduce。

T和U不同的示例

这给了我们很大的自由度,显然,累加器和组合器在这里永远不会相同,因为它们有不同的类型。

我们可能想要聚合的最常见方法之一是收集到一个集合中。我们可以使用reduce它,但由于在 Java 中集合类型通常是可变的,因此使用collect通常会更有效。此规则通常适用:如果结果类型可变,请使用collect而不是reduce。

确定数字流的范围

class Range {
  static Range NONE = new Range(Double.NaN, Double.NaN);

  final double min, max;

  static Range of(double min, double max) {
    if(Double.isNaN(min) || Double.isNaN(max) || min>max) {
      throw new IllegalArgumentException();
    }
    return new Range(min, max);
  }

  private Range(double min, double max) {
    this.min = min;
    this.max = max;
  }

  boolean contains(double value) {
    return this!=Range.NONE && min<=value && max>=value;
  }

  boolean spans(Range other) {
    return this==other
      || other==Range.NONE
      || (contains(other.min) && contains(other.max));
  }

}

Range range = streamOfDoubles.reduce(
    Range.NONE,
    (range, value) -> {
      if(range==Range.NONE)
        return Range.of(value, value);
      else if(range.contains(value))
        return range;
      else
        return Range.of(Math.min(value, range.min), Math.max(value, range.max));
    },
    (a, b) -> {
      if(b.spans(a))
        return b;
      else if(a.spans(b))
        return a;
      else
        return Range.of(Math.min(a.min, b.min), Math.max(a.max, b.max));
    }
);
Run Code Online (Sandbox Code Playgroud)