我已经了解了foldLeft和reducleft的基本区别

foldLeft:

必须传递初始值

reduceLeft:

以集合的第一个元素作为初始值 如果集合为空,则抛出异常

还有其他区别吗?

有什么特殊的原因要有两个功能相似的方法吗?


当前回答

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

java.lang.UnsupportedOperationException: empty.reduceLeft

重写要使用的代码

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

是一个潜在的选择。另一种方法是使用reduceLeftOption变体,它返回一个Option包装的结果。

myList reduceLeftOption {(a,b) => a+b} match {
  case None    => // handle no result as necessary
  case Some(v) => println(v)
}

其他回答

reducleft只是一个方便的方法。它等价于

list.tail.foldLeft(list.head)(_)

规模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

在给出实际答案之前,有几件事需要提一下:

你的问题和左边没有任何关系,而是关于还原和折叠之间的区别 区别根本不在于实现,而在于签名。 这个问题与Scala无关,而是关于函数式编程的两个概念。

回到你的问题:

下面是foldLeft的签名(也可以是foldRight,因为我要说明的观点):

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

这是reduceLeft的签名(方向也不重要)

def reduceLeft [B >: A] (f: (B, A) => B): B

这两个看起来非常相似,因此造成了混淆。reducelleft是foldLeft的一种特殊情况(顺便说一下,这意味着有时可以使用它们中的任何一个来表示相同的东西)。

当你在一个列表[Int]上调用reducelefleft时,它会将整个整数列表缩减为一个值,这将是Int类型(或Int的超类型,因此[B >: a])。

当你在一个列表[Int]上调用foldLeft时,它会将整个列表(想象滚动一张纸)折叠成一个单独的值,但这个值甚至不需要与Int相关(因此[B])。

这里有一个例子:

def listWithSum(numbers: List[Int]) = numbers.foldLeft((List.empty[Int], 0)) {
   (resultingTuple, currentInteger) =>
      (currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}

该方法接受一个List[Int]并返回一个Tuple2[List[Int], Int]或(List[Int], Int)。它计算和并返回一个包含整数列表的元组和它的和。顺便说一下,这个列表是向后返回的,因为我们用的是foldLeft而不是foldRight。

请观看One Fold,以获得更深入的解释。

为了真正理解折叠/缩减的作用, 检查这个:http://wiki.tcl.tk/17983 非常好的解释。一旦你掌握了折叠的概念, Reduce会和上面的答案一起出现: list.tail.foldLeft (list.head) (_)

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

java.lang.UnsupportedOperationException: empty.reduceLeft

重写要使用的代码

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

是一个潜在的选择。另一种方法是使用reduceLeftOption变体,它返回一个Option包装的结果。

myList reduceLeftOption {(a,b) => a+b} match {
  case None    => // handle no result as necessary
  case Some(v) => println(v)
}