如何在scala中使用ListBuffer?

rjc*_*rjc 8 scala

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

代码是这样的:

val ct = List(5)

someMethod(ct)

println (ct(0))

// should print 6
Run Code Online (Sandbox Code Playgroud)

......

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

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

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

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

par*_*tic 10

在scala中,表达式为:

ct(0) = ct(0) + 1
Run Code Online (Sandbox Code Playgroud)

被重写为:

ct.update( 0, ct.apply(0) + 1 )
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果您需要通过索引访问元素,请使用ArrayBuffer.它应该像java一样工作ArrayList.

最后,如果你不需要考虑WithFilter事情.只需使用该filter方法.


inc*_*rop 5

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


Kev*_*ght 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
Run Code Online (Sandbox Code Playgroud)

另一方面,如果这性能热点,并且您无法通过更改算法来识别任何提高性能的方法,那么您将需要使用Array

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

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