在Scala中foldLeft和reduceLeft之间的区别
我学到了foldLeft
和reduceLeft
的基本区别
foldLeft:
- 初始值必须通过
reduceLeft:
- 将集合的第一个元素作为初始值
- 抛出exception,如果收集是空的
还有其他的区别吗?
有两个具有相似function的方法的具体原因?
在给出实际答案之前,在这里提到几件事情:
- 你的问题与
left
没有任何关系,而是关于缩小和折叠的区别 - 差别不在于实现,只是看签名。
- 这个问题与Scala没有任何关系,特别是关于函数式编程的两个概念。
回到你的问题:
这里是foldLeft
的签名(也可能是我要做的事情)。
def foldLeft [B] (z: B)(f: (B, A) => B): B
这里是reduceLeft
的签名(这里的方向不重要)
def reduceLeft [B >: A] (f: (B, A) => B): B
这两个看起来很相似,从而造成了混乱。 reduceLeft
是reduceLeft
的一个特殊情况(顺便说一句,你有时可以使用它们中的任何一个来expression相同的事物)。
当你在一个List[Int]
上调用reduceLeft
,它会逐字地将整个整数列表减less到一个单值,这个值将是Int
types(或者超typesInt
,因此[B >: A]
)。
当你在一个List[Int]
上调用foldLeft
,它会将整个列表(想象中滚动一张纸)折成单个值,但这个值甚至不必与Int
(因此[B]
)相关。
这里是一个例子:
def listWithSum(numbers: List[Int]) = numbers.foldLeft((List[Int](), 0)) { (resultingTuple, currentInteger) => (currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2) }
此方法接受List[Int]
并返回Tuple2[List[Int], Int]
或(List[Int] -> Int)
。 它计算总和并返回一个包含整数列表和总和的元组。 顺便说回来,因为我们使用了foldLeft
而不是foldRight
。
reduceLeft
只是一个方便的方法。 这相当于
list.tail.foldLeft(list.head)(_)
foldLeft
更为通用,您可以使用它来生成与最初放置的内容完全不同的东西。而reduceLeft
只能生成相同types或超types集合types的最终结果。 例如:
List(1,3,5).foldLeft(0) { _ + _ } List(1,3,5).foldLeft(List[String]()) { (a, b) => b.toString :: a }
foldLeft
将使用上次折叠结果(首次使用初始值)和下一个值应用封闭。
另一方面, reduceLeft
将首先结合列表中的两个值并将其应用于闭包。 接下来,将其余的值与累计结果结合起来。 看到:
List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }
如果列表为空, foldLeft
可以将初始值作为合法结果呈现。 另一方面,如果在列表中至less找不到一个值,那么reduceLeft
就没有合法的价值。
他们都在Scala标准库的基本原因可能是因为他们都在Haskell标准库(称为foldl
和foldl1
)。 如果reduceLeft
不是,那么在不同的项目中,它通常被定义为一种方便的方法。
作为参考,如果应用于具有以下错误的空容器, reduceLeft
将会出错。
java.lang.UnsupportedOperationException: empty.reduceLeft
修改要使用的代码
myList foldLeft(List[String]()) {(a,b) => a+b}
是一个潜在的select。 另一个是使用reduceLeftOption
variables,它返回一个Option包装结果。
myList reduceLeftOption {(a,b) => a+b} match { case None => // handle no result as necessary case Some(v) => println(v) }
从Scala的函数编程原理 (Martin Odersky)
reduceLeft
函数是用一个更一般的函数reduceLeft
来定义的。
foldLeft
就像reduceLeft
但是将一个累加器z
作为一个附加的参数,当在一个空列表上调用foldLeft
时候返回:
(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x
[与reduceLeft
,在空列表上调用时会引发exception。]
课程(见第5.5讲)提供了这些函数的抽象定义,它们说明了它们的区别,尽pipe它们在使用模式匹配和recursion方面非常相似。
abstract class List[T] { ... def reduceLeft(op: (T,T)=>T) : T = this match{ case Nil => throw new Error("Nil.reduceLeft") case x :: xs => (xs foldLeft x)(op) } def foldLeft[U](z: U)(op: (U,T)=>U): U = this match{ case Nil => z case x :: xs => (xs foldLeft op(z, x))(op) } }
请注意, foldLeft
返回typesU
的值,它不一定与List[T]
types相同,但reduceLeft返回与列表types相同的值。
要真正理解你在做什么fold / reduce,检查这个: http : //wiki.tcl.tk/17983很好的解释。 一旦你得到折叠的概念,减less将与上面的答案一起:list.tail.foldLeft(list.head)(_)