迭代时从地图中删除键/值

时间:2011-10-06 09:09:41

标签: groovy map

我正在创建这样的地图:

def myMap = [:]

映射基本上是键的对象和值的int。当我遍历地图时,我会减少值,如果它为0,我将其删除。我已经尝试了myMap.remove(),但我得到了ConcurrentModificationError - 这很公平。所以我继续使用it.remove(),这给了我奇怪的结果。

基本上,我的代码是:

myMap.each {
    it.value--;

    if( it.value <= 0 )
        it.remove();
}

足够简单。我的问题是,如果我在删除之前和之后打印myMap.size(),它们是相同的。如果我拨打myMap.containsKey( key ),它会给我true,密钥仍在那里。

但是,如果我打印出这样的地图:

myMap.each { System.out.println( "$it.key: $it.value" ); }

我什么都没得到,并且调用myMap.keySet()myMap.values()会返回空白。

任何人都知道发生了什么事?

2 个答案:

答案 0 :(得分:11)

这应该比Tim's answer更有效(因为你只需要在地图上迭代一次)。不幸的是,它也非常冗长

def map = [2:1, 3:4]
def iterator = map.entrySet().iterator()

while (iterator.hasNext()) {

  if (iterator.next().value - 1 <= 0) {
    iterator.remove()
  }
}

// test that it worked
assert map == [3:4]

答案 1 :(得分:6)

你能做这样的事吗:

myMap = myMap.each { it.value-- }.findAll { it.value > 0 }

这将从每个值中减去一个,然后返回一个仅包含值大于零的条目的新映射。

你不应该在Map remove上调用Entry方法,它应该是Map(see line 325 for the Java 7 implementation)内部使用的私有方法,所以你自己调用它将封闭的地图变成各种各样的麻烦(它不知道它正在丢失条目)

Groovy允许你调用私有方法,所以你可以在Java类的后面做这种技巧

编辑 - 迭代器方法

另一种方式是:

myMap.iterator().with { iterator ->
  iterator.each { entry ->
    entry.value--
    if( entry.value <= 0 ) iterator.remove()
  }
}