2013-03-11 25 views
7

tôi phải xử lý một Map <BitSet,List<List<Integer>> MyMapLàm thế nào để giữ cho hai vòng lặp trên bản đồ trong java và loại bỏ các phím ở giữa mà không ConcurrentModificationException

if (key1 contains all of corresponding true bits of key2) 
    Remove from key2 all those values which are common with key1) 

Trong quá trình này, nếu số phần tử trong danh sách giảm xuống dưới một THRESHOLD (người dùng xác định số nguyên dương), nó được loại bỏ. Ngoài ra, nếu Bản đồ chứa danh sách trống, thì khóa tương ứng sẽ bị xóa.

Tôi đang sử dụng đoạn mã sau:

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; 
} 

Nhưng chương trình được đưa ra lỗi:

java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification
at java.util.ArrayList$Itr.next

Ngoài ra, không chắc chắn nếu điều này là cách hiệu quả để mã? Vì Bản đồ chứa ~ 2000 mục nhập. Xin cho biết.

Trả lời

0

Tôi đã từ bỏ việc đọc mã của bạn sau khi nhìn thấy các tên biến như ll1, ll2, list1, list2, it1, it2.. Tuy nhiên, bạn có thể xem số link để biết giải pháp cho một vấn đề tương tự.

+0

Ồ, xin lỗi. Đã đổi tên ll1 thành sublist1 và ll2 thành sublist2. Xin hãy nhìn lại. Tôi không thể nghĩ ra cái tên nào tốt hơn cho nó1 (Iterator 1) và it2 (Iterator 2). Liên kết bạn vừa giới thiệu không chứa hai trình vòng lặp cố gắng sửa đổi bộ sưu tập :-( – Kaur

+0

'S' trong' S.listIterator' là gì? Và 'THRESHOLD' – greenkode

+0

Chỉnh sửa ... Ngưỡng chỉ định tính hợp lệ của danh sách con. – Kaur

0

Bạn không thể sử dụng iterator.remove() trên key của MapSet vì nó chỉ là một "khung nhìn" trên cấu trúc bên trong của bản đồ.

Nhưng bạn có thể sử dụng trình lặp trên mục nhập của bản đồSet(), trong đó mỗi phần tử là một thể hiện của Map.Entry chứa tất cả các mục bản đồ của bạn (cặp khóa/giá trị). Bạn có thể gọi iterator.remove() trên trình lặp này, điều này sẽ loại bỏ cặp khóa/giá trị tương ứng khỏi bản đồ.

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); 

Hy vọng điều đó sẽ hữu ích.

Trân

+0

Bạn không chính xác về 'Map.iterator(). Remove()', ít nhất là nói chung. [Giao diện chỉ định] (http: // docs .oracle.com/javase/6/docs/api/java/util/Map.html # keySet()) mà loại bỏ được hỗ trợ, mặc dù thêm không. – sharakan

1

Một ConcurrentModificationException thể xảy ra khi bộ sưu tập cơ bản được sửa đổi sau khi một Iterator được tạo ra, và thay đổi mà không được thực hiện thông qua các Iterator riêng của mình.

Trong mã của bạn như được viết, chỉ có một nơi có thể xảy ra: tương tác giữa it1it2, là bộ lặp trên cùng một bộ sưu tập. Bất cứ khi nào bạn gọi số remove trên một thiết bị khác, lần khác bạn sẽ đột nhập vào lần sau bạn gọi next.

Có nhiều cách khác nhau để làm việc xung quanh này, nhưng một cách là để tách những gì bạn đang loại bỏ từ bộ sưu tập 'chìa khóa' của bạn từ lặp đi lặp lại của bộ sưu tập mà, như vậy:

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 sẽ sau đó ở trong trạng thái mà bạn mong đợi. Tôi cho rằng đôi khi bạn sẽ muốn gọi số MyMap.keySet().retainAll() hoặc tương tự.