相当于 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
Equivalent of Scala's foldLeft in Java 8
提问by GA1
What is the equivalent of of Scala's great foldLeft
in 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 acc
umulator: 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::new
will be used to create reusable containers which will be later combined.
供应商StringBuilder::new
将用于创建可重复使用的容器,这些容器将在以后合并。
回答by dzs
There is no equivalent of foldLeft
in Java 8's Stream API. As others noted, reduce(identity, accumulator, combiner)
comes close, but it's not equivalent with foldLeft
because it requires the resulting type B
to 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 2
is 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
. foldLeft
is actually more generic than reduce
: you can implement reduce
with foldLeft
but you cannot implement foldLeft
with reduce
.
请注意,任何需要顺序执行的操作都不能用 表示reduce
。foldLeft
实际上是更通用比reduce
:你可以实现reduce
用foldLeft
,但你无法实现foldLeft
用reduce
。
回答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 reduce
that way, and also not Scala's foldLeft
for that matter. Use collect
instead.
但是,您不能以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();
}