foldLeft
我已经了解和之间的基本区别reduceLeft
左折叠:
- 必须传递初始值
减少左:
- 将集合的第一个元素作为初始值
- 如果集合为空,则抛出异常
还有其他区别吗?
有两种具有相似功能的方法的具体原因吗?
foldLeft
我已经了解和之间的基本区别reduceLeft
左折叠:
减少左:
还有其他区别吗?
有两种具有相似功能的方法的具体原因吗?
在给出实际答案之前,这里要提几件事:
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
在 a 上调用 say 时,List[Int]
它实际上会将整个整数列表减少为单个值,该值将是 type Int
(或 的超类型Int
,因此[B >: A]
)。
当你foldLeft
在 a 上调用 say 时,List[Int]
它会将整个列表(想象一下滚动一张纸)折叠成一个值,但这个值甚至不必与Int
(因此[B]
) 相关。
这是一个例子:
def listWithSum(numbers: List[Int]) = numbers.foldLeft((List.empty[Int], 0)) {
(resultingTuple, currentInteger) =>
(currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}
此方法接受 aList[Int]
并返回 a Tuple2[List[Int], Int]
or (List[Int], Int)
。它计算总和并返回一个带有整数列表的元组,它是总和。顺便说一下,列表是向后返回的,因为我们使用foldLeft
而不是foldRight
.
观看One Fold 以统治它们以获得更深入的解释。
reduceLeft
只是一种方便的方法。它相当于
list.tail.foldLeft(list.head)(_)
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
另一方面,如果在列表中找不到至少一个值,则它不具有合法值。
作为参考,reduceLeft
如果应用于具有以下错误的空容器将出错。
java.lang.UnsupportedOperationException: empty.reduceLeft
重新编写代码以使用
myList foldLeft(List[String]()) {(a,b) => a+b}
是一种潜在的选择。另一种是使用reduceLeftOption
返回选项包装结果的变体。
myList reduceLeftOption {(a,b) => a+b} match {
case None => // handle no result as necessary
case Some(v) => println(v)
}
它们都在 Scala 标准库中的基本原因可能是因为它们都在 Haskell 标准库中(称为foldl
and foldl1
)。如果reduceLeft
不是,它通常会被定义为不同项目中的一种方便方法。
来自Scala 中的函数式编程原则(Martin Odersky):
该函数
reduceLeft
是根据更一般的函数定义的foldLeft
。
foldLeft
就像reduceLeft
但是将accumulatorz
作为附加参数,当foldLeft
在空列表上调用时返回:
(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x
[与 相比reduceLeft
,在空列表上调用时会引发异常。]
本课程(见第 5.5 节)提供了这些函数的抽象定义,说明了它们的区别,尽管它们在模式匹配和递归的使用上非常相似。
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
返回一个类型的值U
,它不一定与 的类型相同List[T]
,但 reduceLeft 返回一个与列表相同类型的值)。
要真正了解您在使用折叠/减少做什么,请查看:http ://wiki.tcl.tk/17983 非常好的解释。一旦你了解了折叠的概念,reduce 将与上面的答案一起出现:list.tail.foldLeft(list.head)(_)
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