创buildScala列表的首选方法

有几种方法可以在Scala中构build一个不可变列表(参见下面的devise示例代码)。 你可以使用一个可变的ListBuffer,创build一个var列表并修改它,使用一个尾recursion的方法,也可能是其他我不知道的。

本能地,我使用ListBuffer,但我没有一个很好的理由这样做。 有创build一个列表的首选或惯用的方法,或者有一种方法是最好的方法之一?

 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) } 

ListBuffer是一个可变列表,它具有常量追加和恒定时间转换为List

List是不可变的,并且具有恒定时间的前置和线性时间追加。

您如何构build您的列表取决于您将使用列表的algorithm以及获取元素的顺序。

例如,如果你得到的元素与他们将要使用的顺序相反,那么你可以使用一个List并做前置操作。 无论你使用tail-recursive函数, foldLeft还是其他的东西都不是真正相关的。

如果按照相同顺序获取元素,则使用它们,那么如果性能至关重要,那么ListBuffer最有可能是更好的select。

但是,如果您不在关键path上并且input足够低,则可以稍后reverse列表,或者只是foldRight ,或reverseinput,这是线性时间。

你不做的是使用一个List并追加到它。 这会给你带来更糟糕的performance,而不仅仅是最后的预谋和逆转。

对于简单的情况:

 val list = List(1,2,3) 

🙂

呃..这些对我来说太复杂了。 我可以提议吗?

 def listTestD = (0 to 3).toList 

要么

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

通常通过消除任何variables,你想要关注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) 

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

索引seq将有你需要的一切:

也就是说,你现在可以在IndexedSeq上工作了:

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

我总是比较喜欢List,在“理解”之前使用“fold / reduce”。 然而,如果需要嵌套的“折叠”,则“理解”是优选的。 如果我不能使用“fold / reduce / for”完成任务,recursion是最后的手段。

所以对于你的例子,我会做:

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

在我做之前:

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

注意:由于“_”的顺序,我在这里使用“foldRight(:\)”而不是“foldLeft(/ :)”。 对于不抛出StackOverflowException的版本,请使用“foldLeft”。

像这样使用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) 

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

Scala集合类将在Scala 2.8之后进行重新devise,所以要尽快改变你创build列表的方式。

什么是创build列表的前向兼容的方式? 我不知道,因为我还没有阅读2.8文档。

描述收集类build议更改的PDF文档

作为一名新的Scala开发者,我使用上面提出的方法编写了一个小testing来检查列表创build时间。 它看起来像(对(p < – (0到x))产生p)toList最快的方法。

 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") } } } 

只是一个使用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)