相当于 Java 8 中 Scala 的 foldLeft

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41240414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:46:00  来源:igfitidea点击:

Equivalent of Scala's foldLeft in Java 8

javajava-8reducefoldleft

提问by GA1

What is the equivalent of of Scala's great foldLeftin Java 8?

ScalafoldLeft在 Java 8 中的伟大相当于什么?

I was tempted to think it was reduce, but reduce has to return something of identical type to what it reduces on.

我很想认为它是reduce,但是 reduce 必须返回与它所减少的相同类型的东西。

Example:

例子:

import java.util.List;

public class Foo {

    // this method works pretty well
    public int sum(List<Integer> numbers) {
        return numbers.stream()
                      .reduce(0, (acc, n) -> (acc + n));
    }

    // this method makes the file not compile
    public String concatenate(List<Character> chars) {
        return chars.stream()
                    .reduce(new StringBuilder(""), (acc, c) -> acc.append(c)).toString();
    }
}

The problem in the code above is the accumulator: new StringBuilder("")

上面代码中的问题是acc模拟器:new StringBuilder("")

Thus, could anyone point me to the proper equivalent of the foldLeft/fix my code?

因此,有人能指出我正确的foldLeft/fix my code 的等价物吗?

采纳答案by Lachezar Balev

Update:

更新:

Here is initial attempt to get your code fixed:

这是修复代码的初步尝试:

public static String concatenate(List<Character> chars) {
        return chars
                .stream()
                .reduce(new StringBuilder(),
                                StringBuilder::append,
                                StringBuilder::append).toString();
    }

It uses the following reduce method:

它使用以下reduce方法

<U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);

It may sound confusing but if you look at the javadocs there is a nice explanation that may help you quickly grasp the details. The reduction is equivalent to the following code:

这听起来可能令人困惑,但如果您查看 javadoc,有一个很好的解释可以帮助您快速掌握细节。减少相当于以下代码:

U result = identity;
for (T element : this stream)
     result = accumulator.apply(result, element)
return result;

For a more in-depth explanation please check this source.

如需更深入的解释,请查看此来源

This usage is not correct though because it violates the contract of reduce which states that the accumulator should be an associative, non-interfering, stateless function for incorporating an additional element into a result. In other words since the identity is mutable the result will be broken in case of parallel execution.

但这种用法并不正确,因为它违反了 reduce 的约定,该约定规定累加器应该是一个关联的、无干扰的、无状态的函数,用于将附加元素合并到结果中。换句话说,由于身份是可变的,因此在并行执行的情况下结果将被破坏。

As pointed in the comments below a correct option is using the reduction as follows:

正如下面的评论中所指出的,正确的选择是使用如下缩减:

return chars.stream().collect(
     StringBuilder::new, 
     StringBuilder::append, 
     StringBuilder::append).toString();

The supplier StringBuilder::newwill be used to create reusable containers which will be later combined.

供应商StringBuilder::new将用于创建可重复使用的容器,这些容器将在以后合并。

回答by dzs

There is no equivalent of foldLeftin Java 8's Stream API. As others noted, reduce(identity, accumulator, combiner)comes close, but it's not equivalent with foldLeftbecause it requires the resulting type Bto combine with itself and be associative (in other terms, be monoid-like), a property that not every type has.

foldLeft在 Java 8 的 Stream API 中没有等效项。正如其他人指出的那样,reduce(identity, accumulator, combiner)接近,但它不等价于,foldLeft因为它需要结果类型B与自身组合并具有关联性(换句话说,类似于幺半群),这是不是每个类型都具有的属性。

There is also an enhancement request for this: add Stream.foldLeft() terminal operation

对此还有一个增强请求:添加Stream.foldLeft()终端操作

To see why reduce won't work, consider the following code, where you intend to execute a series of arithmetic operations starting with given number:

要了解为什么 reduce 不起作用,请考虑以下代码,您打算在其中执行一系列以给定数字开头的算术运算:

val arithOps = List(('+', 1), ('*', 4), ('-', 2), ('/', 5))
val fun: (Int, (Char, Int)) => Int = {
  case (x, ('+', y)) => x + y
  case (x, ('-', y)) => x - y
  case (x, ('*', y)) => x * y
  case (x, ('/', y)) => x / y
}
val number = 2
arithOps.foldLeft(number)(fun) // ((2 + 1) * 4 - 2) / 5

If you tried writing reduce(2, fun, combine), what combiner function could you pass that combines two numbers? Adding the two numbers together clearly does not solve it. Also, the value 2is clearly not an identityelement.

如果您尝试编写reduce(2, fun, combine),您可以传递什么组合器函数来组合两个数字?将两个数字加在一起显然不能解决问题。此外,该值2显然不是标识元素。

Note that no operation that requires a sequential execution can be expressed in terms of reduce. foldLeftis actually more generic than reduce: you can implement reducewith foldLeftbut you cannot implement foldLeftwith reduce.

请注意,任何需要顺序执行的操作都不能用 表示reducefoldLeft实际上是更通用比reduce:你可以实现reducefoldLeft,但你无法实现foldLeftreduce

回答by J?rg W Mittag

The method you are looking for is java.util.Stream.reduce, particularly the overload with three parameters, identity, accumulator, and binary function. That is the correct equivalent to Scala's foldLeft.

您正在寻找的方法是java.util.Stream.reduce,特别是具有三个参数,身份,累加器和二元函数的重载。这与 Scala 的foldLeft.

However, you are notallowed to use Java's reducethat way, and also not Scala's foldLeftfor that matter. Use collectinstead.

但是,您不能reduce这种方式使用 Java ,因此也不能使用 Scala foldLeft。使用collect来代替。

回答by Gagandeep Kalra

Others are correct there's no equivalent though. Here's a util that comes close-

其他人是正确的,但没有等价物。这是一个接近的实用程序-

<U, T> U foldLeft(Collection<T> sequence, U identity, BiFunction<U, ? super T, U> accumulator) {
    U result = identity;
    for (T element : sequence)
        result = accumulator.apply(result, element);
    return result;
}

your case using the above method would look like-

您使用上述方法的情况看起来像-

public String concatenate(List<Character> chars) {
    return foldLeft(chars, new StringBuilder(""), StringBuilder::append).toString();
}

Or without the lambda method ref sugar,

或者没有 lambda 方法参考糖,

public String concatenate(List<Character> chars) {
    return foldLeft(chars, new StringBuilder(""), (stringBuilder, character) -> stringBuilder.append(character)).toString();
}