斯卡拉:折叠与折叠左

Posted

技术标签:

【中文标题】斯卡拉:折叠与折叠左【英文标题】:Scala : fold vs foldLeft 【发布时间】:2013-04-13 05:59:12 【问题描述】:

我试图了解 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)

为什么fold 不能作为foldLeft 工作? Serializable with Equals 是什么?我了解 fold 和 foldLeft 在参数泛型类型方面的 API 签名略有不同。请指教。谢谢。

【问题讨论】:

Difference between fold and foldLeft or foldRight?的可能重复 什么版本的scala? 我的scala版本是2.10.1 推荐你看***.com/questions/25158780/… 【参考方案1】:

fold 方法(最初是为并行计算添加的)在可以应用的类型方面不如foldLeft 强大。它的签名是:

def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1

这意味着完成折叠的类型必须是集合元素类型的超类型。

def foldLeft[B](z: B)(op: (B, A) => B): B

原因是fold可以并行实现,而foldLeft不能。这不仅是因为*Left 部分意味着foldLeft 按顺序从左到右,还因为运算符op 不能合并并行计算的结果——它只定义了如何合并聚合类型@ 987654330@ 元素类型为A,但不知道如何组合B 类型的两个聚合。而fold 方法确实定义了这一点,因为聚合类型A1 必须是元素类型A 的超类型,即A1 &gt;: A。这种超类型关系允许同时折叠聚合和元素,以及组合聚合——两者都使用单个运算符。

但是,聚合和元素类型之间的这种超类型关系也意味着您示例中的聚合类型A1 应该是(ArrayBuffer[Int], Int) 的超类型。由于聚合的零元素是 ArrayBuffer(1, 2, 4, 5) 类型的 ArrayBuffer[Int],因此聚合类型被推断为这两者的超类型 - 那是 Serializable with Equals,元组和数组的唯一最小上限缓冲区。

一般来说,如果你想允许任意类型的并行折叠(这是无序的),你必须使用方法aggregate,它需要定义两个聚合的组合方式。在你的情况下:

r.aggregate(ArrayBuffer(1, 2, 4, 5))( (x, y) => x -- y._1 , (x, y) => x intersect y)

顺便说一句,尝试使用reduce/reduceLeft 编写您的示例——由于这两种方法都具有元素类型和聚合类型之间的超类型关系,您会发现它会导致与你描述的那个。

【讨论】:

以上是关于斯卡拉:折叠与折叠左的主要内容,如果未能解决你的问题,请参考以下文章

当文章的内容超过折叠时,容器上的左填充

左关联二叉树折叠

缩小、折叠或扫描(左/右)?

完美转发与底层原理剖析(引用折叠)

完美转发与底层原理剖析(引用折叠)

Bootstrap 4导航栏右对齐在移动设备上不折叠的按钮