Preferred way to create a Scala list

There are several ways to construct an immutable list in Scala (see contrived example code below). You can use a mutable ListBuffer, create a var list and modify it, use a tail recursive method, and probably others that I don't know about.

Instinctively, I use the ListBuffer, but I don't have a good reason for doing so. Is there a preferred or idiomatic method for creating a list, or are there situations that are best for one method over another?

import scala.collection.mutable.ListBuffer


// THESE are all the same as: 0 to 3 toList.
def listTestA() ={
var list:List[Int] = Nil


for(i <- 0 to 3)
list = list ::: List(i)
list
}




def listTestB() ={
val list = new ListBuffer[Int]()


for (i <- 0 to 3)
list += i
list.toList
}




def listTestC() ={
def _add(l:List[Int], i:Int):List[Int] = i match {
case 3 => l ::: List(3)
case _ => _add(l ::: List(i), i +1)
}
_add(Nil, 0)
}
112891 次浏览

ListBuffer是一个可变的列表,它具有常量时间附加,并且常量时间转换为 List

List是不变的,具有常数时间前置和线性时间后置。

How you construct your list depends on the algorithm you'll use the list for and the order in which you get the elements to create it.

例如,如果元素的使用顺序与使用时间相反,那么可以使用 List进行 prepend。无论是使用尾递归函数 foldLeft还是其他什么方法,这都是无关紧要的。

如果您按照使用元素的顺序获取元素,那么如果性能非常关键,那么 ListBuffer很可能是更好的选择。

但是,如果您没有在一个关键路径和输入是足够低的,您总是可以 reverse的列表,或只是 foldRight,或 reverse的输入,这是线性时间。

不要所做的就是使用一个 List并附加到它上面。这将给你更糟糕的性能比只是预先和反向在结束。

Uhmm.. these seem too complex to me. May I propose

def listTestD = (0 to 3).toList

或者

def listTestE = for (i <- (0 to 3).toList) yield i

我总是喜欢列表,我使用“折叠/减少”之前的“理解”。但是,如果需要嵌套的“折叠”,则首选“理解”。如果我不能使用“ old/reduce/for”完成任务,递归是最后的手段。

举个例子,我会这样做:

((0 to 3) :\ List[Int]())(_ :: _)

在我动手之前:

(for (x <- 0 to 3) yield x).toList

注意: 我在这里使用“ foldRight (:)”而不是“ foldLeft (/:)”,因为顺序是“ _”。对于不抛出 StackOverflow Exception 的版本,使用“ foldLeft”代替。

And for simple cases:

val list = List(1,2,3)

:)

注意: 这个答案是为旧版本的 Scala 编写的。

从 Scala 2.8开始,Scala 集合类将被重新设计,所以要准备好尽快改变创建列表的方式。

创建 List 的向前兼容方式是什么?我不知道,因为我还没看过2.8的文件。

描述集合类的拟议更改的 PDF 文档

您希望通过消除任何 var 来关注 Scala 中的不可变性。 可读性对你的同胞来说仍然很重要,所以:

试试:

scala> val list = for(i <- 1 to 10) yield i
list: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

在大多数情况下,您可能甚至不需要转换为列表:)

索引序列将包含您需要的所有内容:

也就是说,您现在可以处理 IndexedSeq:

scala> list.foldLeft(0)(_+_)
res0: Int = 55

作为一个新的 Scala 开发人员,我编写了一个小测试来检查列表创建时间和上面建议的方法。看起来(for (p <-(0 to x))的结果是 p) to 列出最快的方法。

import java.util.Date
object Listbm {


final val listSize = 1048576
final val iterationCounts = 5
def getCurrentTime: BigInt = (new Date) getTime


def createList[T] ( f : Int => T )( size : Int ): T = f ( size )


// returns function time execution
def experiment[T] ( f : Int => T ) ( iterations: Int ) ( size :Int ) : Int  = {


val start_time = getCurrentTime
for ( p <- 0 to iterations )  createList ( f ) ( size )
return (getCurrentTime - start_time) toInt


}


def printResult ( f:  => Int ) : Unit = println ( "execution time " + f  )


def main( args : Array[String] ) {




args(0) match {


case "for" =>  printResult ( experiment ( x => (for ( p <- ( 0 to x ) ) yield p) toList  ) ( iterationCounts ) ( listSize ) )
case "range"  =>  printResult ( experiment ( x => ( 0 to x ) toList ) ( iterationCounts ) ( listSize ) )
case "::" => printResult ( experiment ( x => ((0 to x) :\ List[Int]())(_ :: _) ) ( iterationCounts ) ( listSize ) )
case _ => println ( "please use: for, range or ::\n")
}
}
}

像这样使用 List.tabulate,

List.tabulate(3)( x => 2*x )
res: List(0, 2, 4)


List.tabulate(3)( _ => Math.random )
res: List(0.935455779102479, 0.6004888906328091, 0.3425278797788426)


List.tabulate(3)( _ => (Math.random*10).toInt )
res: List(8, 0, 7)

只是一个使用 Collection.breakOut 的示例

scala> val a : List[Int] = (for( x <- 1 to 10 ) yield x * 3)(collection.breakOut)
a: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30)


scala> val b : List[Int] = (1 to 10).map(_ * 3)(collection.breakOut)
b: List[Int] = List(3, 6, 9, 12, 15, 18, 21, 24, 27, 30)