简体   繁体   English

在删除和更新集合时遍历 HashMap

[英]Iterating through a HashMap while removing AND updating the collection

I have a count map where I keep track of the numbers of characters from a string.我有一个计数图,我在其中跟踪字符串中的字符数。 I want to iterate over that map, decrement the currently visited character count AND remove it if it reaches zero.我想遍历该地图,减少当前访问的字符数,如果达到零则将其删除。

How can that be done in Java?在 Java 中如何做到这一点?

HashMap<Character, Integer> characterCount = new HashMap<>();
characterCount.put('a', 2);
characterCount.put('b', 1);
characterCount.put('c', 1);

Iterator<Map.Entry<Character, Integer>> iterator = characterCount.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<Character, Integer> entry = iterator.next();

    // Decrement the chosen character from the map
    if (entry.getValue() == 1) {
        iterator.remove();
    } else {
        characterCount.put(entry.getKey(), entry.getValue() - 1);
    }

    // Call some logic the relies on the map with the remaining character count.
    // I want the characterCount.size() to return zero when there is no character with count > 0
    doSomeLogic(characterCount);

    // Restore the character to the map
    characterCount.put(entry.getKey(), entry.getValue());
}

The above code results in a ConcurrentModificationException .上面的代码导致ConcurrentModificationException

Since Map#entrySet returns a view of the mappings in the map, directly set the value of the Entry to update it.由于Map#entrySet返回映射中映射的视图,因此直接设置Entry的值以对其进行更新。

if (entry.getValue() == 1) {
    iterator.remove();
} else {
    entry.setValue(entry.getValue() - 1);
}

Here is one way.这是一种方法。 Map.computeIfPresent will remove the entry when it becomes null . Map.computeIfPresent将在条目变为null时删除它。 Using the ternary operator either decrements the value or replaces with null if it is presently 1 (about to be decremented).使用三元运算符要么递减值,要么在当前为1 (即将递减)时用null替换。

Map<Character, Integer> map = new HashMap<>();
map.put('a', 2);
map.put('b', 1);
map.put('c', 1);

map.computeIfPresent('c', (k,v)-> v == 1 ? null : v-1);
map.computeIfPresent('a', (k,v)-> v == 1 ? null : v-1);

System.out.println(map);

prints印刷

{a=1, b=1}

So, here is how it would work for you, replacing your iterator and while loop.所以,这就是它如何为你工作,替换你的迭代器和 while 循环。

for (char ch : characterCount.keySet()) {
      characterCount.computeIfPresent(ch, (k,v)-> v == 1 ? null : v-1);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM