不了解 Scala 中 foldLeft 和 foldRight 的效率不同
Don't understand efficiency is different in foldLeft and foldRight in Scala
阅读 Scala 编程,第 2 版中的以下段落对我来说没有意义。
def flattenLeft[T](xss: List[List[T]]) =
(List[T]() /: xss) (_ ::: _)
def flattenRight[T](xss: List[List[T]]) =
(xss :\ List[T]()) (_ ::: _)
Because list concatenation, xs ::: ys
, takes time proportional to its
first argument xs, the implementation in terms of fold right in
flattenRight is more efficient than the fold left implementation in
flattenLeft . The problem is that flattenLeft(xss) copies the first
element list xss.head n − 1 times, where n is the length of the list
xss
因此,如果列表连接所花费的时间与其 first 参数成正比,这是否意味着 flattenLeft
效率更高,因为它的第一个参数是一个空列表并且flattenRight
的第一个参数是未知长度的列表?
foldLeft
的第一个参数只是开头的一个空List
,即本次折叠的zero
。
当您将所有 List
折叠到一个 List
时,fold
构建中间列表,其中包含每次连接的部分结果,然后用作下一个连接的参数级联。这个中间结果越来越大。在 foldLeft
上,这将是第一个参数:
def flattenLeft[T](xss: List[List[T]]) =
(List[T]() /: xss) ((acc, xs) => acc ::: xs )
//^ this one
相反,对于 foldRight
你从右边构建结果,这意味着中间结果(增长的那个)是右边的,这将是连接操作的第二个参数
def flattenRight[T](xss: List[List[T]]) =
(xss :\ List[T]()) ((xs, acc) => xs ::: acc)
//^ this one gets bigger now
因此,flattenRight
将花费更少的时间,因为连接的第一个参数不会随着您的进展而增长。
通过从左侧折叠来展平列表
[ [....] [....] [....] [....] [....] ]
[....]
[...........]
[..................]
[.........................]
[................................]
从右边开始为
[ [....] [....] [....] [....] [....] ]
[....]
[...........]
[..................]
[.........................]
[................................]
当从左边折叠 n 个列表时,第一个列表中的每个元素被跟踪 (n-1) 次;在第二个列表中 (n-2) 次,等等。这是经典的二次行为。
当从右侧折叠时,每个元素都被精确地追踪 一次,以获得整个操作的线性行为。
阅读 Scala 编程,第 2 版中的以下段落对我来说没有意义。
def flattenLeft[T](xss: List[List[T]]) =
(List[T]() /: xss) (_ ::: _)
def flattenRight[T](xss: List[List[T]]) =
(xss :\ List[T]()) (_ ::: _)
Because list concatenation,
xs ::: ys
, takes time proportional to its first argument xs, the implementation in terms of fold right in flattenRight is more efficient than the fold left implementation in flattenLeft . The problem is that flattenLeft(xss) copies the first element list xss.head n − 1 times, where n is the length of the list xss
因此,如果列表连接所花费的时间与其 first 参数成正比,这是否意味着 flattenLeft
效率更高,因为它的第一个参数是一个空列表并且flattenRight
的第一个参数是未知长度的列表?
foldLeft
的第一个参数只是开头的一个空List
,即本次折叠的zero
。
当您将所有 List
折叠到一个 List
时,fold
构建中间列表,其中包含每次连接的部分结果,然后用作下一个连接的参数级联。这个中间结果越来越大。在 foldLeft
上,这将是第一个参数:
def flattenLeft[T](xss: List[List[T]]) =
(List[T]() /: xss) ((acc, xs) => acc ::: xs )
//^ this one
相反,对于 foldRight
你从右边构建结果,这意味着中间结果(增长的那个)是右边的,这将是连接操作的第二个参数
def flattenRight[T](xss: List[List[T]]) =
(xss :\ List[T]()) ((xs, acc) => xs ::: acc)
//^ this one gets bigger now
因此,flattenRight
将花费更少的时间,因为连接的第一个参数不会随着您的进展而增长。
通过从左侧折叠来展平列表
[ [....] [....] [....] [....] [....] ]
[....]
[...........]
[..................]
[.........................]
[................................]
从右边开始为
[ [....] [....] [....] [....] [....] ]
[....]
[...........]
[..................]
[.........................]
[................................]
当从左边折叠 n 个列表时,第一个列表中的每个元素被跟踪 (n-1) 次;在第二个列表中 (n-2) 次,等等。这是经典的二次行为。
当从右侧折叠时,每个元素都被精确地追踪 一次,以获得整个操作的线性行为。