我已经了解了foldLeft
和reduceLeft
foldLeft:
reduceLeft:
还有其他区别吗?
有两种方法具有相似功能的任何特定原因吗?
答案 0 :(得分:280)
在给出实际答案之前,这里很少提及:
left
没有任何关系,而是与缩小和折叠之间的区别回到你的问题:
以下是foldLeft
的签名(对于我要提出的观点,也可能是foldRight
):
def foldLeft [B] (z: B)(f: (B, A) => B): B
这里是reduceLeft
的签名(这里方向无关紧要)
def reduceLeft [B >: A] (f: (B, A) => B): B
这两个看起来非常相似,因而引起了混乱。 reduceLeft
是foldLeft
的一个特例(顺便说一下,有时可以通过使用其中任何一个来表达相同的内容)。
当你在reduceLeft
上调用List[Int]
时,它会将整个整数列表减少为单个值,该值将为Int
类型(或超类型) Int
,因此[B >: A]
)。
当你在foldLeft
上打电话List[Int]
时,它会将整个列表(想象一张纸)折叠成一个值,但这个值甚至不必与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
。
观看One Fold to rule them all以获得更深入的解释。
答案 1 :(得分:182)
reduceLeft
只是一种方便的方法。它相当于
list.tail.foldLeft(list.head)(_)
答案 2 :(得分:43)
foldLeft
更通用,您可以使用它来生成与您最初放入的内容完全不同的内容。而reduceLeft
只能生成相同类型或超类型集合的最终结果类型。例如:
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
可以将初始值显示为合法结果。另一方面,reduceLeft
如果在列表中找不到至少一个值,则没有合法值。
答案 3 :(得分:5)
它们都在Scala标准库中的基本原因可能是因为它们都在Haskell标准库中(称为foldl
和foldl1
)。如果没有reduceLeft
,则通常会将其定义为不同项目中的便捷方法。
答案 4 :(得分:5)
作为参考,reduceLeft
如果应用于具有以下错误的空容器,则会出错。
java.lang.UnsupportedOperationException: empty.reduceLeft
重新编写代码以使用
myList foldLeft(List[String]()) {(a,b) => a+b}
是一个潜在的选择。另一种方法是使用返回Option包装结果的reduceLeftOption
变体。
myList reduceLeftOption {(a,b) => a+b} match {
case None => // handle no result as necessary
case Some(v) => println(v)
}
答案 5 :(得分:2)
来自Functional Programming Principles in Scala(Martin Odersky):
函数
reduceLeft
是根据更一般的函数foldLeft
定义的。
foldLeft
与reduceLeft
类似,但需要累加器z
作为附加参数,在foldLeft
上调用时会返回该参数空列表:
(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x
[与reduceLeft
相反,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)
}
}
在空列表中调用时抛出异常。]
该课程(见讲座5.5)提供了这些函数的抽象定义,这些定义说明了它们之间的差异,尽管它们在模式匹配和递归的使用方面非常相似。
foldLeft
请注意,U
返回类型为List[T]
的值,其类型不一定与if (session_status() == PHP_SESSION_NONE) {
session_start();
}
相同,但reduceLeft返回与列表类型相同的值。 / p>
答案 6 :(得分:0)
要真正理解你在做什么用fold / reduce, 检查一下:http://wiki.tcl.tk/17983 非常好的解释。一旦你得到折叠的概念, 减少将与上面的答案一起: list.tail.foldLeft(list.head)(_)
答案 7 :(得分:0)
Scala 2.13.3,演示:
val names = List("Foo", "Bar")
println("ReduceLeft: "+ names.reduceLeft(_+_))
println("ReduceRight: "+ names.reduceRight(_+_))
println("Fold: "+ names.fold("Other")(_+_))
println("FoldLeft: "+ names.foldLeft("Other")(_+_))
println("FoldRight: "+ names.foldRight("Other")(_+_))
输出:
ReduceLeft: FooBar
ReduceRight: FooBar
Fold: OtherFooBar
FoldLeft: OtherFooBar
FoldRight: FooBarOther