在地图上重复和删除[复制]

时间:2021-01-05 19:15:59

This question already has an answer here:

这个问题已经有了答案:

I was doing:

我在做:

for (Object key : map.keySet())
    if (something)
        map.remove(key);

which threw a ConcurrentModificationException, so i changed it to:

它抛出了一个ConcurrentModificationException,所以我将它改为:

for (Object key : new ArrayList<Object>(map.keySet()))
    if (something)
        map.remove(key);

this, and any other procedures that modify the map are in synchronized blocks.

这和任何其他修改地图的程序都是同步的。

is there a better solution?

有更好的解决方案吗?

if no one comes up with a better solution, first to say no gets the tick ;)

如果没有人想出更好的解决方案,先说“不”;

12 个解决方案

#1


334  

Here is a code sample to use the iterator in a for loop to remove the entry.

这里有一个代码示例,用于在for循环中使用迭代器来删除条目。

    Map<String, String> map = new HashMap<String, String>() {
      {
        put("test", "test123");
        put("test2", "test456");
      }
    };

    for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); it.hasNext(); ) {
      Map.Entry<String, String> entry = it.next();
      if(entry.getKey().equals("test")) {
        it.remove();
      }
    }

#2


145  

As of Java 1.8 you could do this using lambda expressions and streams:

在Java 1.8中,您可以使用lambda表达式和流来实现这一点:

map.entrySet().removeIf(e-> <boolean expression> );

#3


88  

Use a real iterator.

使用一个真正的迭代器。

Iterator<Object> it = map.keySet().iterator();

while (it.hasNext())
{
  it.next();
  if (something)
    it.remove();
 }

Actually, you might need to iterate over the entrySet() instead of the keySet() to make that work.

实际上,您可能需要遍历entrySet()而不是keySet()来完成该工作。

#4


40  

is there a better solution?

有更好的解决方案吗?

Well, there is, definitely, a better way to do so in a single statement, but that depends on the condition based on which elements are removed.

当然,在单个语句中有更好的方法,但这取决于移除元素的条件。

For eg: remove all those elements where value is test, then use below:

例如:删除所有那些值为测试的元素,然后在下面使用:

map.values().removeAll(Collections.singleton("test"));

UPDATE It can be done in a single line using Lambda expression in Java 8.

可以在Java 8中使用Lambda表达式在单行中进行更新。

map.entrySet().removeIf(e-> <boolean expression> );

I know this question is way too old, but there isn't any harm in updating the better way to do the things :)

我知道这个问题太老了,但是更新更好的方法并没有什么害处。

#5


19  

ConcurrentHashMap

ConcurrentHashMap

You can use java.util.concurrent.ConcurrentHashMap.

您可以使用java.util.concurrent.ConcurrentHashMap。

It implements ConcurrentMap (which extends the Map interface).

它实现了ConcurrentMap(扩展了Map接口)。

E.g.:

例如:

Map<Object, Content> map = new ConcurrentHashMap<Object, Content>();

for (Object key : map.keySet()) {
    if (something) {
        map.remove(key);
    }
}

This approach leaves your code untouched. Only the map type differs.

这种方法使您的代码不受影响。只有地图类型不同。

#6


6  

Java 8 support a more declarative approach to iteration, in that we specify the result we want rather than how to compute it. Benefits of the new approach are that it can be more readable, less error prone.

Java 8支持一个更声明性的迭代方法,在这个过程中,我们指定了我们想要的结果,而不是如何计算它。新方法的优点是它可以更容易读,更容易出错。

public static void mapRemove() {
    Map<Integer, String> map = new HashMap<Integer, String>() {
        {
            put(1, "one");
            put(2, "two");
            put(3, "three");
        }
    };
    map.forEach( (key, value) -> { System.out.println( "Key: " + key + "\t" + " Value: " + value ); }); 
    map.keySet().removeIf(e->(e>2));
    System.out.println("After removing element");
    map.forEach( (key, value) -> { System.out.println( "Key: " + key + "\t" + " Value: " + value ); });

}

And result is as follows:

结果如下:

Key: 1   Value: one
Key: 2   Value: two
Key: 3   Value: three
After removing element
Key: 1   Value: one
Key: 2   Value: two

#7


4  

You have to use Iterator to safely remove element while traversing a map.

在遍历映射时,必须使用Iterator安全地删除元素。

#8


2  

I agree with Paul Tomblin. I usually use the keyset's iterator, and then base my condition off the value for that key:

我同意保罗·汤姆布林的观点。我通常使用keyset的迭代器,然后根据该键的值将条件设置为:

Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
    Integer key = it.next();
    Object val = map.get(key);
    if (val.shouldBeRemoved()) {
        it.remove();
    }
}

#9


1  

Maybe you can iterate over the map looking for the keys to remove and storing them in a separate collection. Then remove the collection of keys from the map. Modifying the map while iterating is usually frowned upon. This idea may be suspect if the map is very large.

也许您可以遍历映射,查找要删除的键并将它们存储在单独的集合中。然后从映射中删除键的集合。在迭代时修改映射通常是不赞成的。如果地图很大,这个想法可能会被怀疑。

#10


0  

An alternative, more verbose way

一种更详细的选择。

List<SomeObject> toRemove = new ArrayList<SomeObject>();
for (SomeObject key: map.keySet()) {
    if (something) {
        toRemove.add(key);
    }
}

for (SomeObject key: toRemove) {
    map.remove(key);
}

#11


0  

And this should work as well..

这也应该奏效。

running is ConcurrentMap<Integer, String> 
Set<Entry<Integer, String>> set = running.entrySet();


for (Entry<Integer, String> entry : set )
{ 
  if (entry.getKey()>600000)
  {
    set.remove(entry);    
  }
}

#12


-1  

         Set s=map.entrySet();
         Iterator iter = s.iterator();
         while (iter.hasNext()) 
         {
         Map.Entry entry =(Map.Entry)iter.next();
         if("value you need to remove".equals(entry.getKey()))
         {
         map.remove();
         }
         }

#1


334  

Here is a code sample to use the iterator in a for loop to remove the entry.

这里有一个代码示例,用于在for循环中使用迭代器来删除条目。

    Map<String, String> map = new HashMap<String, String>() {
      {
        put("test", "test123");
        put("test2", "test456");
      }
    };

    for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); it.hasNext(); ) {
      Map.Entry<String, String> entry = it.next();
      if(entry.getKey().equals("test")) {
        it.remove();
      }
    }

#2


145  

As of Java 1.8 you could do this using lambda expressions and streams:

在Java 1.8中,您可以使用lambda表达式和流来实现这一点:

map.entrySet().removeIf(e-> <boolean expression> );

#3


88  

Use a real iterator.

使用一个真正的迭代器。

Iterator<Object> it = map.keySet().iterator();

while (it.hasNext())
{
  it.next();
  if (something)
    it.remove();
 }

Actually, you might need to iterate over the entrySet() instead of the keySet() to make that work.

实际上,您可能需要遍历entrySet()而不是keySet()来完成该工作。

#4


40  

is there a better solution?

有更好的解决方案吗?

Well, there is, definitely, a better way to do so in a single statement, but that depends on the condition based on which elements are removed.

当然,在单个语句中有更好的方法,但这取决于移除元素的条件。

For eg: remove all those elements where value is test, then use below:

例如:删除所有那些值为测试的元素,然后在下面使用:

map.values().removeAll(Collections.singleton("test"));

UPDATE It can be done in a single line using Lambda expression in Java 8.

可以在Java 8中使用Lambda表达式在单行中进行更新。

map.entrySet().removeIf(e-> <boolean expression> );

I know this question is way too old, but there isn't any harm in updating the better way to do the things :)

我知道这个问题太老了,但是更新更好的方法并没有什么害处。

#5


19  

ConcurrentHashMap

ConcurrentHashMap

You can use java.util.concurrent.ConcurrentHashMap.

您可以使用java.util.concurrent.ConcurrentHashMap。

It implements ConcurrentMap (which extends the Map interface).

它实现了ConcurrentMap(扩展了Map接口)。

E.g.:

例如:

Map<Object, Content> map = new ConcurrentHashMap<Object, Content>();

for (Object key : map.keySet()) {
    if (something) {
        map.remove(key);
    }
}

This approach leaves your code untouched. Only the map type differs.

这种方法使您的代码不受影响。只有地图类型不同。

#6


6  

Java 8 support a more declarative approach to iteration, in that we specify the result we want rather than how to compute it. Benefits of the new approach are that it can be more readable, less error prone.

Java 8支持一个更声明性的迭代方法,在这个过程中,我们指定了我们想要的结果,而不是如何计算它。新方法的优点是它可以更容易读,更容易出错。

public static void mapRemove() {
    Map<Integer, String> map = new HashMap<Integer, String>() {
        {
            put(1, "one");
            put(2, "two");
            put(3, "three");
        }
    };
    map.forEach( (key, value) -> { System.out.println( "Key: " + key + "\t" + " Value: " + value ); }); 
    map.keySet().removeIf(e->(e>2));
    System.out.println("After removing element");
    map.forEach( (key, value) -> { System.out.println( "Key: " + key + "\t" + " Value: " + value ); });

}

And result is as follows:

结果如下:

Key: 1   Value: one
Key: 2   Value: two
Key: 3   Value: three
After removing element
Key: 1   Value: one
Key: 2   Value: two

#7


4  

You have to use Iterator to safely remove element while traversing a map.

在遍历映射时,必须使用Iterator安全地删除元素。

#8


2  

I agree with Paul Tomblin. I usually use the keyset's iterator, and then base my condition off the value for that key:

我同意保罗·汤姆布林的观点。我通常使用keyset的迭代器,然后根据该键的值将条件设置为:

Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
    Integer key = it.next();
    Object val = map.get(key);
    if (val.shouldBeRemoved()) {
        it.remove();
    }
}

#9


1  

Maybe you can iterate over the map looking for the keys to remove and storing them in a separate collection. Then remove the collection of keys from the map. Modifying the map while iterating is usually frowned upon. This idea may be suspect if the map is very large.

也许您可以遍历映射,查找要删除的键并将它们存储在单独的集合中。然后从映射中删除键的集合。在迭代时修改映射通常是不赞成的。如果地图很大,这个想法可能会被怀疑。

#10


0  

An alternative, more verbose way

一种更详细的选择。

List<SomeObject> toRemove = new ArrayList<SomeObject>();
for (SomeObject key: map.keySet()) {
    if (something) {
        toRemove.add(key);
    }
}

for (SomeObject key: toRemove) {
    map.remove(key);
}

#11


0  

And this should work as well..

这也应该奏效。

running is ConcurrentMap<Integer, String> 
Set<Entry<Integer, String>> set = running.entrySet();


for (Entry<Integer, String> entry : set )
{ 
  if (entry.getKey()>600000)
  {
    set.remove(entry);    
  }
}

#12


-1  

         Set s=map.entrySet();
         Iterator iter = s.iterator();
         while (iter.hasNext()) 
         {
         Map.Entry entry =(Map.Entry)iter.next();
         if("value you need to remove".equals(entry.getKey()))
         {
         map.remove();
         }
         }