有几种方法可以在Scala中构造不可变列表(请参阅下面的设计示例代码)。您可以使用可变的ListBuffer,创建var
列表并对其进行修改,使用tail recursive方法,以及其他我不了解的方法。
本能地,我使用ListBuffer,但我没有充分的理由这样做。有没有首选或惯用的方法来创建列表,还是有一种方法最适合一种方法而不是另一种方法?
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)
}
答案 0 :(得分:107)
ListBuffer
是一个可变列表,具有常量时间追加和恒定时间转换为List
。
List
是不可变的,并且具有常量时间前置和线性时间追加。
如何构建列表取决于您将使用列表的算法以及获取元素的顺序。
例如,如果您按照与使用时相反的顺序获取元素,那么您可以使用List
并执行前置。你是否会使用尾递归函数,foldLeft
或其他东西并不真正相关。
如果您使用相同顺序的元素,那么如果性能至关重要,则ListBuffer
最有可能成为首选。
但是,如果您没有处于关键路径且输入足够低,您可以随后reverse
列表,或仅foldRight
或reverse
输入,是线性时间。
不要做的是使用List
并附加到它。这将使您的性能远远低于最后的前置和后退。
答案 1 :(得分:65)
对于简单的案例:
val list = List(1,2,3)
:)
答案 2 :(得分:22)
def listTestD = (0 to 3).toList
或
def listTestE = for (i <- (0 to 3).toList) yield i
答案 3 :(得分:5)
您希望通过消除任何变量来关注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
答案 4 :(得分:2)
我总是喜欢List而我在“for comprehension”之前使用“fold / reduce”。但是,如果需要嵌套的“折叠”,则“理解”是优选的。如果我无法使用“fold / reduce / for”完成任务,则递归是最后的手段。
所以对于你的例子,我会这样做:
((0 to 3) :\ List[Int]())(_ :: _)
在我做之前:
(for (x <- 0 to 3) yield x).toList
注意:由于“_”的顺序,我在这里使用“foldRight(:\)”而不是“foldLeft(/ :)”。对于不抛出StackOverflowException的版本,请改用“foldLeft”。
答案 5 :(得分:2)
注意:此答案是针对旧版本的Scala编写的。
Scala集合类将从Scala 2.8开始重新设计,因此请准备好尽快更改创建列表的方式。
创建List的前向兼容方式是什么?我不知道,因为我还没有读过2.8文档。
A PDF document describing the proposed changes of the collection classes
答案 6 :(得分:2)
使用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)
答案 7 :(得分:1)
作为一名新的scala开发人员,我使用上面建议的方法编写了一个小测试来检查列表创建时间。看起来(对于(p < - (0到x))产生p)来列出最快的方法。
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")
}
}
}
答案 8 :(得分:0)
只是一个使用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)
答案 9 :(得分:0)
要创建字符串列表,请使用以下命令:
val l = List("is", "am", "are", "if")