Удалить ключ / значение из карты во время итерации - PullRequest
6 голосов
/ 06 октября 2011

Я создаю карту следующим образом:

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 ]

11 голосов
/ 06 октября 2011

Это должно быть немного эффективнее, чем Ответ Тима (потому что вам нужно только итерировать по карте один раз).К сожалению, это также довольно многословно

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]
6 голосов
/ 06 октября 2011

Можете ли вы сделать что-то вроде этого:

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

Это вычтет одно из каждого значения, а затем вернет вам новую карту только тех записей, где значение больше нуля.

Вы не должны вызывать метод remove на карте Entry, он должен быть закрытым методом, используемым внутри карты ( см. Строку 325 для реализации Java 7 ), так что, если вы называете это сами, то включаете прилагаемую Карту во все виды беспокойства (она не знает, что теряет записи)

Groovy позволяет вам вызывать закрытые методы, так что вы можете выполнять подобные хитрости за спиной Java-классов

Edit - метод итератора

Другой способ будет:

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