为什么scala reduce()和reduceLeft()以相同的方式减少值序列?
如果我跑步:为什么scala reduce()和reduceLeft()以相同的方式减少值序列?,scala,collections,Scala,Collections,如果我跑步: List(1, 4, 3, 9).reduce {(a, b) => println(s"$a + $b"); a + b} 结果是: 1 + 4 5 + 3 8 + 9 但是,如果我使用reduceLeft而不是reduce,它还会打印: 1 + 4 5 + 3 8 + 9 我认为reduce以这种方式减少了值的顺序: (1+4) + (3+9) (5) + (12) (17) reduceLeft和reduce之间的真正区别是什么?区别在于:
List(1, 4, 3, 9).reduce {(a, b) => println(s"$a + $b"); a + b}
结果是:
1 + 4
5 + 3
8 + 9
但是,如果我使用reduceLeft
而不是reduce
,它还会打印:
1 + 4
5 + 3
8 + 9
我认为reduce
以这种方式减少了值的顺序:
(1+4) + (3+9)
(5) + (12)
(17)
reduceLeft
和reduce
之间的真正区别是什么?区别在于:
reduce
可以按任意顺序进行reduce;对于列表
而言,它恰好与reduceLeft
相同,因为它更高效(因此,它们中的大多数都是相同的)。对于另一个集合,它可能相当于reduceRight
,对于树类型,它可能更符合您的预期
reduce[B >: A](op: (B, B) => B): B
对
reduceLeft[B >: A](op: (B, A) => B): B
因为reduceLeft
中op
的第一个参数始终是调用它的集合的元素,但是对于reduce
来说,它可能是递归reduce
调用的结果
看看这两个函数的类型:
def reduce[B >: A](op: (B, B) => B): B
def reduceLeft[B >: A](op: (B, A) => B): B
请注意,reduceLeft
中op
的第二个参数是A
(与元素类型相同),而在reduce
中是B
(与返回值相同)
这是一个重要的区别。reduce中的操作必须是关联的,这意味着您可以将列表拆分为多个部分,分别对每个部分应用该操作,然后再次将其应用于要合并的结果
当您希望并行执行操作时,这一点很重要:reduce
可以并行应用于列表的不同部分,然后可以组合结果
另一方面,reduceLeft
只能按顺序工作(顾名思义,从左到右),操作不必是关联的,并且可以期望其第二个参数始终是序列的一个元素(第一个参数是迄今为止操作的结果)
考虑
val sum = (1 to 100).reduce(_ + _)
这将产生与(1到100)相同的结果。reduceLeft(+u-)
,只是前者可以并行化。
另一方面:
val strings = (1 to 100).reduceLeft[Any](_.toString + ";" + _.toString)
不应写为reduce
(即使在这个人为的示例中,只要您坚持串行处理,它就可以,甚至可以工作),因为结果取决于元素输入操作的顺序。“我认为reduce以这种方式减少了值的顺序:”ham no.reduce
的大多数实现只是回退到reduceLeft
,但它们可能回退到reduceRight
-reduce
只是不能保证操作的顺序,如果您不关心订单,请使用reduce
,因为基础集合将选择最有效的订单,如果您需要从左到右或从右到左选择其他订单之一;区别更多的是语义,而不是真正的实现细节。如果您想要总是并行搜索的内容,请搜索aggregate