在Scala中/:和:\运算符之间的性能考虑

时间:2012-05-07 00:40:10

标签: scala scala-collections

我觉得insertSortRight的效率低于insertSortLeft,因为insertSortRight需要调用List.last(它是O(n))作为insert()的参数之一,其中insertSortLeft调用List.head(它是O(1) )作为insert()的参数之一。

这种理解是否正确?感谢。

def insertSortRight(unsorted: List[Int]) : List[Int] = {
  (unsorted :\ List[Int]()) ((a, b) => insert(a, b))
}

def insertSortLeft(unsorted: List[Int]) : List[Int] = {
  (List[Int]() /: unsorted) ((a, b) => insert(b, a))
}  

def insert(a: Int, list: List[Int]) : List[Int] = list match {
  case List() => List(a)
  case y::ys => if (a > y) y::insert(a, ys) else a::y::ys
}
DHG回答“总是喜欢左折叠”。但是,Scala中的Programming有另一种方式。

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

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

我想这是因为在这种情况下flattenRight只通过一个函数调用实现,而flattenLeft是通过n函数调用实现的?

1 个答案:

答案 0 :(得分:4)

因此,对于List,由于需要进行头部操作,foldLeft是自然的选择。这样你就可以从左到右完成列表,总是先行。如您所见,它的实现(在LinearSeqOptimized上)只使用while循环并遍历一次。

override /*TraversableLike*/
def foldLeft[B](z: B)(f: (B, A) => B): B = {
  var acc = z
  var these = this
  while (!these.isEmpty) {
    acc = f(acc, these.head)
    these = these.tail
  }
  acc
}

似乎'foldRight'将是O(n ^ 2),因为为了获取最后一个元素,您必须遍历List n 元素> n 次,但图书馆实际上为您优化了这一点。在幕后,foldRight就像这样实现(也在LinearSeqOptimized上):

def foldRight[B](z: B)(f: (A, B) => B): B =
  if (this.isEmpty) z
  else f(head, tail.foldRight(z)(f))

正如您所看到的,此函数是通过在尾部递归调用foldRight,将每个头保持在堆栈上,并在到达最后一个元素后以相反的顺序将函数应用于每个头来构造的。