java - 使用不同的组合器和累加器进行流缩减的示例

标签 java java-stream

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

其中一个要求是combiner函数必须与accumulator函数兼容;对于所有 u 和 t,必须满足以下条件:

 combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t) (*) 

如果combineraccumulator相同,则上述等式自动成立。

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

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

stream.reduce(id, op, op);

当然,人们不能总是使用 combineracumulator因为在一般情况下,它们有不同的用途并且是不同的 Java 类型。

我的问题

是否有一个具有不同 combiner 的流减少示例和accumulator

此外,我对琐碎的示例不感兴趣,而是对并行流减少时在实践中遇到的自然示例感兴趣。

对于简单的例子,有很多教程,例如this one

我为什么问这个问题

基本上,这种缩减方法存在的原因是为了并行流。在我看来,条件(*)是如此强大,以至于在实践中,它使得这种归约毫无用处,因为归约操作很少满足它。

最佳答案

组合器和累加器是否相同?你在这里混淆了事情。

accumulatorX 转换至Y例如(使用身份),而 combiner合并两个Y合而为一。另请注意,其中一个是 BiFunction另一个是 BinaryOperator (实际上是 BiFunction<T, T, T> )。

Is there an example of stream reduction with distinct combiner and accumulator?

这些对我来说看起来很不同:

    Stream.of("1", "2")
          .reduce(0, (x, y) -> x + y.length(), Integer::sum);

认为您可能会对以下内容感到困惑:

Stream.of("1", "2")
      .reduce("", String::concat, String::concat);

怎么办?

BiFunction<String, String, String> bi = String::concat;

嗯,有一个 hint here

编辑

解决“不同”意味着不同操作的部分,accumulator可能sum ,而accumulator可能multiply 。这正是规则:

combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

是为了保护自己免受两个独立关联函数的影响,但操作不同。让我们以两个列表(相等,但顺序不同)为例。顺便说一句,如果有 Set::of 会更有趣。来自java-9添加 an internal randomization ,因此理论上来说,对于相同的输入,您在同一虚拟机上每次运行都会得到不同的结果。但为了简单起见:

List.of("a", "bb", "ccc", "dddd");
List.of("dddd", "a", "bb", "ccc");

我们想要执行:

....stream()
   .parallel()
   .reduce(0,
          (x, y) -> x + y.length(),
          (x, y) -> x * y);

当前实现下,这将为两个列表产生相同的结果;但这是一个实现工件

没有什么可以阻止内部实现:“我会将列表拆分为可能的最小块,但每个 block 中不小于两个元素”。在这种情况下,这可以转换为这些分割:

["a",    "bb"]     ["ccc", "dddd"]
["dddd", "a" ]     ["bb" , "ccc" ]   

现在,“累积”这些分割:

0 + "a".length   = 1 ; 1 + "bb".length   = 3 // thus chunk result is 3
0 + "ccc".length = 3 ; 3 + "dddd".length = 7 // thus chunk result is 7 

现在我们“组合”这些 block :3 * 7 = 21 .

我很确定您已经看到在这种情况下第二个列表将导致 25 ;因此累加器和组合器中的不同操作可能会导致错误的结果。

关于java - 使用不同的组合器和累加器进行流缩减的示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58980110/

相关文章:

Java RMI - 检查注册表是否存在

java - 无法在 Android Studio 1.0.1 中使用导入的 jar

java - 如何在使用收集器收集元素时合并列表/集合

java - 查找流中直到该元素为止满足条件的第一个元素

Java列表映射功能不起作用

java-8 - 如何将 List<Person> 转换为 Map<String,List<Employee>>

java - Spring MVC + hibernate : How to handle form with relation

java - Spring Cron 表达式 "*/5 * * * * ?"的含义

java - Jenkins:为不同的 URL 部署不同的 applicationContext

java - 如何在java中将一个列表类型转换为另一个列表?