[英]How to keep two iterators over map in java and remove keys in between without ConcurrentModificationException
I have to process a Map <BitSet,List<List<Integer>> MyMap
我必须处理Map <BitSet,List<List<Integer>> MyMap
if (key1 contains all of corresponding true bits of key2)
Remove from key2 all those values which are common with key1)
In this process, if the number of elements in a list drops below a THRESHOLD (user defined positive integer), it is removed. 在此过程中,如果列表中的元素数量低于THRESHOLD(用户定义的正整数),则将其删除。 Also if the Map contains empty list, then corresponding key is removed. 此外,如果Map包含空列表,则删除相应的键。
I am using following code: 我使用以下代码:
List<BitSet> keys = new ArrayList<>(MyMap.keySet());
ListIterator it1=keys.listIterator();
while(it1.hasNext()) {
BitSet key1=(BitSet)it1.next();
ListIterator it2=keys.listIterator(it1.nextIndex());
while(it2.hasNext()) {
BitSet key2=(BitSet)it2.next();
BitSet ankey=(BitSet)key1.clone();
ankey.and(key2);
if(ankey.equals(key1)) {//key1 is subset and key2 is superset
if(removePoints(key1,key2)) {
it1.remove();
break;
}
}
else if(ankey.equals(key2)) {
if(removePoints(key2,key1)) {
it2.remove();
}
}
}
}
public static boolean removePoints(BitSet key1,BitSet key2)
{
List<List<Integer>> list1=MyMap.get(key1);
List<List<Integer>> list2=MyMap.get(key2);
Boolean ret=false;
for(int i=0;i<list1.size();i++) {
List<Integer> sublist1=list1.get(i);
for(int j=0;j<list2.size();j++) {
List<Integer> sublist2=list2.get(j);
sublist1.removeAll(sublist2);
if(sublist1.isEmpty())
break;
}
if(sublist1.size()<=THRESHOLD)
list1.remove(sublist1);
if( list1.isEmpty()) {
MyMap.remove(key1);
ret=true;
}
}
return ret;
}
But the program is giving error: 但该程序给出了错误:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification
at java.util.ArrayList$Itr.next
Also, am not sure if this is the efficient way to code? 此外,我不确定这是否是有效的代码方式? As the Map contain ~2000 entries. 由于地图包含~2000个条目。 Please advise. 请指教。
A ConcurrentModificationException
can happen when the underlying collection is modified after an Iterator
is created, and that modification isn't done through the Iterator
itself. 在创建Iterator
之后修改基础集合时,可能会发生ConcurrentModificationException
,并且不会通过Iterator
本身进行修改。
In your code as written, there is only one place where that can happen: the interation between it1
and it2
, which are iterators on the same collection. 在您编写的代码中,只有一个地方可以发生: it1
和it2
之间的交互,它们是同一集合上的迭代器。 Anytime you call remove
on one, the other one will break the next time you call next
. 任何时候你打电话给remove
一个,另一个将在你next
打电话时打破。
There's a variety of ways to work around this, but one way is to separate what you're removing from your 'key' collection from the iteration of that collection, like so: 有多种方法可以解决这个问题,但有一种方法是将您从'key'集合中删除的内容与该集合的迭代分开,如下所示:
List<BitSet> allKeys = new ArrayList<>(MyMap.keySet());
List<BitSet> removedKeys = new ArrayList<>();
for (ListIterator<BitSet> it1 = allKeys.listIterator(); it1.hasNext(); ) {
BitSet key1 = it1.next();
for (ListIterator<BitSet> it2 = allKeys.listIterator(it1.nextIndex()); it2.hasNext(); ) {
BitSet key2 = it2.next();
BitSet ankey=(BitSet)key1.clone();
ankey.and(key2);
if(ankey.equals(key1)) {//key1 is subset and key2 is superset
if(removePoints(key1,key2)) {
removedKeys.add(key1);
break;
}
}
else if(ankey.equals(key2)) {
if(removePoints(key2,key1)) {
removedKeys.add(key2);
break;
}
}
}
}
allKeys.removeAll(removedKeys);
allKeys
will then be in the state that you expect. allKeys
将处于您期望的状态。 I assume that sometime later you would want to call MyMap.keySet().retainAll()
or similar. 我假设以后你想要调用MyMap.keySet().retainAll()
或类似的东西。
You can not use iterator.remove() on the Map's keySet since it's only a "view" on the internal structure of the map. 你不能在Map的keySet上使用iterator.remove(),因为它只是地图内部结构的“视图”。
But you can use an iterator on the map's entrySet(), where each element is an instance of Map.Entry containing all you map entries (key/value pairs). 但是您可以在map的entrySet()上使用迭代器,其中每个元素都是包含所有映射条目(键/值对)的Map.Entry实例。 You can call iterator.remove() on this iterator, that will effectivly remove the corresponding key/value pair from the map. 您可以在此迭代器上调用iterator.remove(),这将有效地从地图中删除相应的键/值对。
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(Integer.valueOf(0), "0");
map.put(Integer.valueOf(1), "1");
map.put(Integer.valueOf(2), "2");
map.put(Integer.valueOf(3), "3");
map.put(Integer.valueOf(4), "4");
System.out.println(map);
Iterator<Map.Entry<Integer, String>> entryIter = map.entrySet().iterator();
while (entryIter.hasNext()) {
Map.Entry<Integer, String> entry = entryIter.next();
if (entry.getKey().intValue() % 2 == 0)
entryIter.remove();
}
System.out.println(map);
Hope that it helps. 希望它有所帮助。
Regards 问候
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.