如何在scala中使用ListBuffer?

时间:2011-07-04 10:15:44

标签: scala

我遇到的情况是我将单个元素列表传递给方法。在此方法中,列表中的单个元素增加1。因此,在方法调用之后,列表第一个元素被修改(递增1)。

代码是这样的:

val ct = List(5)

someMethod(ct)

println (ct(0))

// should print 6

...

//within somethod, I incrment the element like:
def someMethod(ct: List[Int}) {
    ct(0) = ct(0) + 1
}

当然上面的代码在Scala中不起作用。我看了ListBuffer,但我发现scala doc难以理解。 Scala doc分为2组:Type Member和Value Members。在类型成员中有类WithFiler,值成员有许多方法。我如何使用WithFiler(可能与此问题没有直接关系,但我想了解如何使用scala doc)。

ListBuffer似乎是解决这个问题的正确方法,如果我想获得非常高的性能(someMethod被称为数百万次)(如果我错了,请纠正我)。

那么如果ListBuffer是正确的列表类型,如果没有解决方案,如何解决上述问题?

5 个答案:

答案 0 :(得分:10)

在scala中,表达式为:

ct(0) = ct(0) + 1

被重写为:

ct.update( 0, ct.apply(0) + 1 )

没有为超类型update定义方法List,因为列表可以是不可变的。但是,这是函数参数的类型。

所以你必须只使用ListBuffers(或一个可变的超类型):

def someMethod(ct: ListBuffer[Int]) {
  ct(0) = ct(0) + 1
}

scala> val lst = ListBuffer( 5 )
  lst: scala.collection.mutable.ListBuffer[Int] = ListBuffer(5)
scala> someMethod( lst )
scala> lst
  res2: scala.collection.mutable.ListBuffer[Int] = ListBuffer(6)

顺便说一句,如果您需要按索引访问元素,请使用ArrayBuffer。它应该用作java ArrayList

最后,如果你不需要考虑WithFilter的东西。只需使用filter方法。

答案 1 :(得分:5)

如果性能是主要目标并且已知最大集合大小,则可以使用直接映射到java数组的Array。

答案 2 :(得分:5)

这有一种过早的微观优化的气味。

虽然使用可变性(包括优化)有正当理由,但您没有说明为什么您认为您的使用有效,或者您尝试解决的更大问题。特别是,当获取尾部并增加一个新头时,不可变列表非常效率 - 100%的非头元素将在原始列表和新列表之间共享。

如上所述,最符合您要求的解决方案是忘记ListBuffer,坚持使用不可变List并实施someMethod而无需借助副作用。

def someMethod(xs: List[Int]) = xs match {
  case h :: t => (h+1) :: t
  case Nil => Nil
}

val ct = List(5)
println (someMethod(ct).headOption getOrElse "empty list")

// should print 6

另一方面,如果此 是性能热点,并且您无法通过更改算法找出提高性能的任何方法,那么您将需要使用{{1} }

Array是JVM上唯一的reified集合类型。因此,您可以直接使用数组中的基元,并避免其他集合类型必须应对的装箱/取消装箱。

这里的优势与可变性和不变性无关;取消装箱/装箱的性能成本远远高于使用不可变列表的性能成本(如果有的话)。

答案 3 :(得分:2)

您当然可以重写上述内容以使用ListBuffer,但如果您想要的只是单个Int的逐个引用语义,那么它不一定是最有效的解决方案。 ArrayBuffer应该会好一些。你也可以这样做:

class IntCell(var x: Int)
def someMethod(ct: IntCell) {
  ct.x += 1
}

我经常尝试重写我的代码以避免使用可变集合来处理这类事情。例如,您只需返回新值:

def someMethod(ct: Int) = ct + 1

答案 4 :(得分:2)

如果你想使用ListBuffer,你所要做的就是在代码中用“ListBuffer”替换单词“List”。但是,我会完全像naten建议的那样避免副作用功能(你的someMethod:Unit)。

ListBuffer具有“高性能” - 但是,主要目的是添加项目/修改集合。如果我正确地得到它,你只需要在一个项目集合中更新项目数百万次 - 数组就足够了。