在Scala中foldLeft和reduceLeft之间的区别

我学到了foldLeftreduceLeft的基本区别

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 

这两个看起来很相似,从而造成了混乱。 reduceLeftreduceLeft的一个特殊情况(顺便说一句,你有时可以使用它们中的任何一个来expression相同的事物)。

当你在一个List[Int]上调用reduceLeft ,它会逐字地将整个整数列表减less到一个单值,这个值将是Inttypes(或者超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标准库(称为foldlfoldl1 )。 如果reduceLeft不是,那么在不同的项目中,它通常被定义为一种方便的方法。

作为参考,如果应用于具有以下错误的空容器, reduceLeft将会出错。

 java.lang.UnsupportedOperationException: empty.reduceLeft 

修改要使用的代码

 myList foldLeft(List[String]()) {(a,b) => a+b} 

是一个潜在的select。 另一个是使用reduceLeftOptionvariables,它返回一个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)(_)