在删除某些元素时,如何迭代Scala ArrayBuffer?

时间:2016-06-03 03:53:41

标签: scala for-loop arraylist arraybuffer

我有一些来自游戏的Scala代码,用于在onInteract(gameData: GameData, player: Player)GameObject的{​​{1}}的每个实例上调用mutable.ArrayBuffer方法。但是,有时这些gameobjects会使用代码GameObjectArrayBuffer中删除自己。由于这会改变gameobjects -= this,Scala会抛出ArrayBuffer。代码可以被认为类似于以下内容:

NullPointerException

并且每当删除一个对象时都会抛出异常。

我该如何解决这个问题?我想象一下for (gameobject <- gameobjects) { if (/* some condition */) gameobjects -= gameobject } 或至少ArrayBuffer循环不适用于此。

2 个答案:

答案 0 :(得分:1)

虽然我无法在scala 2.11.8中重现异常,但您可以看到结果不正确:

import scala.collection.mutable.ArrayBuffer
val a = ArrayBuffer(1, 2, 2, 3)

for (x <- a) {
   if (x == 2) a-=x
}

// There's still a 2!
a: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

我怀疑发生了这种情况,因为当你开始迭代时,数组现在拥有更少的元素。

更好的,更加scala的方法是使用filter(或filterNot):

val a = ArrayBuffer(1, 2, 2, 3)
a.filter { _ != 2 } // == ArrayBuffer(1, 3)

答案 1 :(得分:1)

使用-=删除ArrayBuffer中的内容非常慢 - 您必须逐个元素搜索才能找到它,然后将所有内容随机播放到缓冲区的末尾。无论如何,你可能不应该这样做。

如果要同时进行迭代和删除,则应使用支持此功能的数据结构。 java.util.concurrent.ConcurrentHashMap通常是一个不错的选择,如果你想通过身份查找你的对象并且你不会有重复。

例如:

val chm = new java.util.concurrent.ConcurrentHashMap[String, Int]
chm put ("fish", 1); chm put ("dish", 2); chm put ("wish", 3)
val e = chm.keys
e.hasMoreElements // true
e.nextElement     // "wish"
e.hasMoreElements // true
chm remove "fish"
chm remove "dish" // empty now!!
e.nextElement     // "dish"--was going to be the next key
e.hasMoreElements // false--now it realizes chm is empty
chm get "dish"    // null, because it doesn't exist

使用Scala集合完全复制这种行为有点困难,所以为了保证您的安全,您可能希望像上面那样做一些事情。