有几种方法可以在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)
}
9 回答
ListBuffer
是一个可变列表,具有常量时间追加和恒定时间转换为List
.List
是不可变的,并且具有常量时间前置和线性时间追加 .如何构建列表取决于您将使用列表的算法以及获取元素的顺序 .
例如,如果您按照与使用它们相反的顺序获取元素,那么您可以使用
List
并执行前置 . 你是否会使用尾递归函数,foldLeft
或其他东西并不是真正相关的 .如果你按照相同的顺序获得元素,那么如果性能至关重要,那么
ListBuffer
很可能是一个更好的选择 .但是,如果您没有处于关键路径并且输入足够低,您可以在以后的列表中始终
reverse
,或者只是foldRight
或reverse
输入,这是线性时间 .你 DON'T 做的是使用
List
并追加它 . 这将使您的性能远远低于最后的前置和后退 .对于简单的情况:
:)
嗯......这些对我来说似乎太复杂了 . 我可以提议吗?
要么
您希望通过消除任何变量来关注Scala中的不变性 . 可读性对于你的同伴来说仍然很重要,所以:
尝试:
在大多数情况下,您甚至可能不需要转换为列表:)
索引的seq将包含您需要的一切:
也就是说,您现在可以处理IndexedSeq:
我总是喜欢List,我在“for comprehension”之前使用“fold / reduce” . 但是,如果需要嵌套的“折叠”,则“理解”是优选的 . 如果我无法使用“fold / reduce / for”完成任务,则递归是最后的手段 .
所以对于你的例子,我会这样做:
在我做之前:
注意:由于“_”的顺序,我在这里使用“foldRight(:\)”而不是“foldLeft(/ :)” . 对于不抛出StackOverflowException的版本,请改用“foldLeft” .
使用
List.tabulate
,像这样,Note: This answer is written for an old version of Scala.
Scala集合类将从Scala 2.8开始重新设计,因此请准备好尽快更改创建列表的方式 .
什么是创建列表的向前兼容方式?我不知道,因为我还没有读过2.8文档 .
A PDF document describing the proposed changes of the collection classes
作为一个新的scala开发人员,我用上面建议的方法编写了一个小测试来检查列表创建时间 . 看起来(对于(p < - (0到x))产生p)toList最快的方法 .
只是一个使用collection.breakOut的示例