Scala:折叠与折叠左
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16111440/
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
Scala : fold vs foldLeft
提问by thlim
I am trying to understand how fold and foldLeft and the respective reduce and reduceLeft work. I used fold and foldLeft as my example
我试图了解 fold 和 foldLeft 以及相应的 reduce 和 reduceLeft 是如何工作的。我以 fold 和 foldLeft 为例
scala> val r = List((ArrayBuffer(1, 2, 3, 4),10))
scala> r.foldLeft(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)
scala> res28: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(5)
scala> r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)
<console>:11: error: value _1 is not a member of Serializable with Equals
r.fold(ArrayBuffer(1,2,4,5))((x,y) => x -- y._1)
Why folddidn't work as foldLeft? What is Serializable with Equals? I understand fold and foldLeft has slight different API signature in terms of parameter generic types. Please advise. Thanks.
为什么fold不起作用foldLeft?什么是Serializable with Equals?我了解 fold 和 foldLeft 在参数泛型类型方面的 API 签名略有不同。请指教。谢谢。
回答by axel22
The method fold(originally added for parallel computation) is less powerful than foldLeftin terms of types it can be applied to. Its signature is:
该方法fold(最初添加用于并行计算)不如foldLeft它可以应用的类型强大。它的签名是:
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
This means that the type over which the folding is done has to be a supertype of the collection element type.
这意味着完成折叠的类型必须是集合元素类型的超类型。
def foldLeft[B](z: B)(op: (B, A) => B): B
The reason is that foldcan be implemented in parallel, while foldLeftcannot. This is not only because of the *Leftpart which implies that foldLeftgoes from left to right sequentially, but also because the operator opcannot combine results computed in parallel -- it only defines how to combine the aggregation type Bwith the element type A, but not how to combine two aggregations of type B. The foldmethod, in turn, does define this, because the aggregation type A1has to be a supertype of the element type A, that is A1 >: A. This supertype relationship allows in the same time folding over the aggregation and elements, and combining aggregations -- both with a single operator.
原因是fold可以并行实现,而foldLeft不能。这不仅是因为*Left暗示foldLeft从左到右顺序进行的部分,还因为运算符op不能合并并行计算的结果——它只定义了如何将聚合类型B与元素类型组合A,而不是如何组合类型的两个聚合B。fold反过来,该方法确实定义了 this,因为聚合类型A1必须是元素 type 的超类型A,即A1 >: A。这种超类型关系允许同时折叠聚合和元素,并组合聚合——两者都使用单个运算符。
But, this supertype relationship between the aggregation and the element type also means that the aggregation type A1in your example should be the supertype of (ArrayBuffer[Int], Int). Since the zero element of your aggregation is ArrayBuffer(1, 2, 4, 5)of the type ArrayBuffer[Int], the aggregation type is inferred to be the supertype of both of these -- and that's Serializable with Equals, the only least upper bound of a tuple and an array buffer.
但是,聚合和元素类型之间的这种超类型关系也意味着A1示例中的聚合类型应该是(ArrayBuffer[Int], Int). 由于聚合的零元素是ArrayBuffer(1, 2, 4, 5)类型ArrayBuffer[Int],因此推断聚合类型是这两者的超类型——这Serializable with Equals是元组和数组缓冲区的唯一最小上限。
In general, if you want to allow parallel folding for arbitrary types (which is done out of order) you have to use the method aggregatewhich requires defining how two aggregations are combined. In your case:
一般来说,如果你想允许任意类型的并行折叠(这是乱序的),你必须使用aggregate需要定义两个聚合如何组合的方法。在你的情况下:
r.aggregate(ArrayBuffer(1, 2, 4, 5))({ (x, y) => x -- y._1 }, (x, y) => x intersect y)
Btw, try writing your example with reduce/reduceLeft-- because of the supertype relationship between the element type and the aggregation type that both these methods have, you will find that it leads to a similar error as the one you've described.
顺便说一句,请尝试使用reduce/ reduceLeft--编写示例,因为这两种方法都具有元素类型和聚合类型之间的超类型关系,您会发现它会导致与您描述的错误类似的错误。

