不要理解Scala中foldLeft和foldRight的效率不同

时间:2017-01-13 08:12:41

标签: scala fold

阅读Scala编程中的以下段落,第2版对我没有意义。

def flattenLeft[T](xss: List[List[T]]) =
  (List[T]() /: xss) (_ ::: _)

def flattenRight[T](xss: List[List[T]]) =
  (xss :\ List[T]()) (_ ::: _)
  

因为列表连接xs ::: ys需要时间与其成比例   第一个参数xs,在折叠方面的实现   flattenRight比折叠左实现更有效   flattenLeft。问题是flattenLeft(xss)复制了第一个   元素列表xss.head n - 1次,其中n是列表的长度   XSS

因此,如果列表连接需要的时间与其第一个参数成比例,那么意味着flattenLeft更有效率,因为它的第一个参数是一个空列表并且{{1第一个参数是一个未知长度的列表?

2 个答案:

答案 0 :(得分:2)

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将花费更少的时间,因为连接的第一个参数不会随着您的进展而增长。

答案 1 :(得分:2)

通过从左侧折叠来展平列表

[ [....] [....] [....] [....] [....] ]
  [....] 
  [...........] 
  [..................] 
  [.........................] 
  [................................] 

,从右边开始

[ [....] [....] [....] [....] [....] ]
                              [....] 
                       [...........]  
                [..................]  
         [.........................]  
  [................................]  

从左侧折叠 n 列表时,第一个列表中的每个元素都会在(n-1)次上进行追踪;在第二个列表中(n-2)次等。这是经典的二次行为。

从右侧折叠时,每个元素都会在一次之后进行跟踪,以获得总操作的线性行为。