2010-08-18 25 views
5

Possible Duplicates:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over itLàm thế nào tôi có thể lặp qua một đối tượng trong khi sửa đổi nó trong Java?

Tôi đang cố gắng để lặp qua HashMap:

Map<String, Integer> group0 = new HashMap<String, Integer>(); 

... và trích xuất tất cả các phần tử trong group0. Đây là cách tiếp cận của tôi:

// iterate through all Members in group 0 that have not been assigned yet 
for (Map.Entry<String, Integer> entry : group0.entrySet()) { 

    // determine where to assign 'entry' 
    iEntryGroup = hasBeenAccusedByGroup(entry.getKey()); 
    if (iEntryGroup == 1) { 
     assign(entry.getKey(), entry.getValue(), 2); 
    } else { 
     assign(entry.getKey(), entry.getValue(), 1); 
    } 
} 

Vấn đề ở đây là mỗi cuộc gọi đến assign() sẽ loại bỏ các yếu tố từ group0, do đó thay đổi kích thước của nó, do đó gây ra lỗi sau:

Exception in thread "main" java.util.ConcurrentModificationException 
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) 
    at java.util.HashMap$EntryIterator.next(HashMap.java:834) 
    at java.util.HashMap$EntryIterator.next(HashMap.java:832) 
    at liarliar$Bipartite.bipartition(liarliar.java:463) 
    at liarliar$Bipartite.readFile(liarliar.java:216) 
    at liarliar.main(liarliar.java:483) 

Vì vậy, ... làm thế nào tôi có thể lặp qua các phần tử trong group0 trong khi nó tự động thay đổi không?

+2

Tạo bản sao của bản đồ nhóm0 và xóa các phần tử khỏi bản sao trong khi lặp qua nhóm0? – sarahTheButterFly

+0

@ sarah ... điểm tốt. Tôi sẽ thử xem. – Hristo

+0

@sarah ...sao chép trên group0 đến một HashMap bản sao cho tôi vấn đề mà khi tôi loại bỏ từ group0, tôi cũng loại bỏ từ bản sao. Làm thế nào tôi có thể vượt qua điều đó? Làm cách nào để tạo một bản sao độc lập của nhóm0? – Hristo

Trả lời

7

Những người khác đã đề cập đến giải pháp đúng mà không thực sự đánh vần nó. Vì vậy, đây đó là:

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

    // determine where to assign 'entry' 
    iEntryGroup = hasBeenAccusedByGroup(entry.getKey()); 

    if (iEntryGroup == 1) { 
     assign(entry.getKey(), entry.getValue(), 2); 
    } else { 
     assign(entry.getKey(), entry.getValue(), 1); 
    } 

    // I don't know under which conditions you want to remove the entry 
    // but here's how you do it 
    iterator.remove(); 
} 

Ngoài ra, nếu bạn muốn thay đổi một cách an toàn bản đồ chức năng assign của bạn, bạn cần phải vượt qua trong iterator (trong đó bạn chỉ có thể sử dụng chức năng remove và chỉ một lần) hoặc mục nhập để thay đổi giá trị.

+0

Cảm ơn ... đây chính xác là những gì tôi đang tìm kiếm! – Hristo

0

Bạn cần sử dụng trình lặp thực tế và phương thức xóa của nó nếu bạn muốn sửa đổi bộ sưu tập trong khi lặp lại nó. Không có cách nào để làm điều đó với cấu trúc foreach.

Nếu bạn đang cố gắng xóa nhiều mục nhập trong một lần lặp, bạn cần phải lặp lại một thứ không được bản đồ sao lưu.

Set<String> keys = new HashSet<String>(group0.keySet()); 
for (String key : keys) { 
    if (group0.containsKey(key)) { 
    Integer value = group0.get(key); 
    //your stuff 
    } 
} 
+0

'assign()' cũng có khả năng xóa nhiều hơn 1 phần tử khỏi nhóm 0 ... do đó, có khả năng một lần lặp sẽ loại bỏ tất cả các phần tử trong nhóm0 và không cần lặp lại lần thứ hai. Bạn có thể đăng mã cho cách Iterator hoạt động không? – Hristo

0

Trong trường hợp này, cách assign sửa đổi group0? Cần thêm chi tiết. Thông thường bạn không thể sửa đổi một bộ sưu tập trong khi lặp lại nó. Bạn sửa đổi thông qua giao diện Iterator.

3

Như câu trả lời của tôi ở đây nói:

Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

Sử dụng Iterator.remove()

+1

Trong khi liên kết này có thể trả lời câu hỏi, tốt hơn nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. – ProgramFOX

1
+0

.. thú vị. Cám ơn vì sự gợi ý. Bạn có thể chạm nhanh vào các lợi ích hiệu suất của việc sử dụng ConcurrentHashMap không? Có những cải tiến đáng kể trong việc sử dụng cấu trúc dữ liệu như vậy, trong việc kiểm tra xem một phần tử có tồn tại hay không, lấy một phần tử, loại bỏ một phần tử, chèn một phần tử, v.v ...? – Hristo

1

Trong trường hợp cụ thể của bạn, tôi sẽ không sửa đổi cấu trúc của HashMap mà chỉ đơn thuần là null giá trị bạn muốn loại bỏ. Sau đó, nếu bạn kết thúc truy cập một giá trị null chỉ cần bỏ qua nó.

Trong trường hợp chung tôi thích sử dụng ngăn xếp cho những thứ như thế này vì chúng dễ hình dung và vì vậy tôi có ít vấn đề hơn với điều kiện biên giới (chỉ cần giữ popping 'cho đến khi trống).

+0

ahh ... ý tưởng hay :) nhưng việc sử dụng ngăn xếp hoàn toàn không chính xác ở đây ... ví dụ: nếu tôi muốn kiểm tra xem một phần tử có tồn tại hay không, điều đó sẽ vô cùng hiệu quả ở đây. Đối với mục tiêu, hiệu quả và tốc độ của tôi là phải. nhưng tôi thích ý tưởng vô ích. +1 – Hristo

Các vấn đề liên quan