简体   繁体   English

如何在java中将两个迭代器保留在map上,并在没有ConcurrentModificationException的情况下删除其间的键

[英]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. 在您编写的代码中,只有一个地方可以发生: it1it2之间的交互,它们是同一集合上的迭代器。 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()或类似的东西。

I gave up trying to read your code after seeing variable names like ll1, ll2, list1, list2, it1, it2. 在看到ll1, ll2, list1, list2, it1, it2.等变量名后,我放弃了尝试读取代码ll1, ll2, list1, list2, it1, it2. . however you can look at this link for a solution to a similar problem. 但是,您可以查看此链接以获得类似问题的解决方案。

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.

相关问题 Java迭代器如何检测集合被修改抛出ConcurrentModificationException? - How Java iterators detect the collection is modified to throw ConcurrentModificationException? Java在没有ConcurrentModificationException的情况下在同一循环中添加/删除 - Java add/remove at the same loop without ConcurrentModificationException 如何在没有ConcurrentModificationException的情况下删除List迭代 - How to remove List iteration without ConcurrentModificationException 如何在没有ConcurrentModificationException的情况下删除哈希图中的多个映射? - How to remove multiple mappings in hashmap without ConcurrentModificationException? 与迭代器的ConcurrentModificationException - ConcurrentModificationException with Iterators 使用2个迭代器的java.util.ConcurrentModificationException - java.util.ConcurrentModificationException using 2 iterators Java-具有递归方法和嵌套迭代器的ConcurrentModificationException - Java - ConcurrentModificationException with recursive method and nested iterators Java-解析具有2个迭代器和可怕的ConcurrentModificationException的ArrayList - Java - Parsing ArrayList with 2 iterators and the dreaded ConcurrentModificationException 从 ArrayList 同时删除两个对象而不导致 ConcurrentModificationException? - Remove two objects at the same time from an ArrayList without causing a ConcurrentModificationException? 迭代map时出现ConcurrentModificationException - ConcurrentModificationException when iterating over map
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM