2010-08-18 13 views
5

Possible Duplicates:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over itJak mogę iterować nad obiektem podczas modyfikowania go w Javie?

Próbuję pętli HashMap:

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

... i wyodrębnić każdy element w group0. To jest moje podejście:

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

Problemem jest to, że każde wywołanie assign() usunie elementy z group0, modyfikując w ten sposób swój rozmiar, powodując następujący błąd:

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) 

Więc ... jak czy mogę przełączać się między elementami w group0 podczas dynamicznej zmiany?

+2

Wykonaj kopię mapy group0 i usuń elementy z kopii podczas przechodzenia przez grupę0? – sarahTheButterFly

+0

@sarah ... dobry punkt. Spróbuję tego. – Hristo

+0

@sarah ...kopiowanie grupy0 do klonu HashMap daje mi problem, że kiedy usuwam z grupy0, również usuwam z klonu. Jak mogę to pokonać? Jak utworzyć niezależną kopię grupy0? – Hristo

Odpowiedz

7

Inni wspomnieli o poprawnym rozwiązaniu bez wypisywania go. Więc to jest tutaj:

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

Ponadto, jeśli chcesz bezpiecznie zmienić mapę w przypisać funkcję, trzeba przejść w iterator (z których można korzystać tylko z funkcji usunąć i tylko raz) lub wejście, aby zmienić wartość.

+0

Dzięki ... właśnie tego szukam! – Hristo

0

Musisz użyć rzeczywistego iteratora i jego metody usuwania, jeśli chcesz zmodyfikować kolekcję podczas jej pętli. Tak naprawdę nie ma sposobu, aby to zrobić za pomocą konstrukcji foreach.

Jeśli próbujesz usunąć wiele wpisów w jednej iteracji, musisz zapętlić coś, czego nie ma na mapie.

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()' może również potencjalnie usunąć więcej niż 1 elementy z grupy0 ... więc jest szansa, że ​​jedna iteracja usunie wszystkie elementy z grupy0 i nie będzie potrzeby powtórnej iteracji. Czy możesz opublikować kod na temat działania Iteratora? – Hristo

0

W tym przypadku, jak można modyfikować group0assign? Potrzebujemy więcej szczegółów. Zazwyczaj nie można modyfikować kolekcji podczas jej iterowania. Modyfikujesz przez interfejs Iterator.

1
+0

.. interesujące. Dzieki za sugestie. Czy mógłbyś krótko dotknąć korzyści płynących z używania aplikacji ConcurrentHashMap? Czy istnieją znaczące ulepszenia w stosowaniu takiej struktury danych, jeśli chodzi o sprawdzenie, czy element istnieje, pobranie elementu, usunięcie elementu, wstawienie elementu itp. ...? – Hristo

1

W twoim konkretnym przypadku nie modyfikowałbym struktury HashMap, ale tylko null wartość, którą chcesz usunąć. Jeśli skończysz odwiedzać wartość pustą, po prostu ją pomiń.

W ogólnym przypadku wolę używać stosu do takich rzeczy, ponieważ są one szczególnie łatwe do wizualizacji, a więc mam tendencję do mniejszych problemów z warunkami brzegowymi (po prostu utrzymywanie poppingu 'till empty).

+0

ahh ... dobry pomysł :) ale używanie stosu jest tutaj całkowicie niepoprawne ... na przykład gdybym chciał sprawdzić, czy element istnieje, byłoby to absurdalnie nieefektywne. Moim celem jest wydajność i szybkość. ale podoba mi się pomysł zerowania. +1 – Hristo

Powiązane problemy