我遇到的情况是我将单个元素列表传递给方法。在此方法中,列表中的单个元素增加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是正确的列表类型,如果没有解决方案,如何解决上述问题?
答案 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具有“高性能” - 但是,主要目的是添加项目/修改集合。如果我正确地得到它,你只需要在一个项目集合中更新项目数百万次 - 数组就足够了。