创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
,或reverse
input,这是线性时间。
你不做的是使用一个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)