2010-08-18 6 views
5

Possible Duplicates:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over itWie kann ich über ein Objekt iterieren, während ich es in Java ändere?

Ich versuche, eine Schleife durch HashMap:

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

... und in group0 jedes Element zu extrahieren. Das ist mein Ansatz:

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

Das Problem hierbei ist, dass jeder Aufruf assign() Elemente aus group0 zu entfernen, damit seine Größe ändern, wodurch den folgenden Fehler:

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) 

So ... wie kann ich die Elemente in group0 durchlaufen, während es sich dynamisch ändert?

+2

Erstellen Sie eine Kopie der Karte group0 und entfernen Sie Elemente aus der Kopie, während Sie die Gruppe0 durchlaufen? – sarahTheButterFly

+0

@sarah ... guter Punkt. Ich werde es versuchen. – Hristo

+0

@sarah ...Kopieren über Group0 auf einen Klon HashMap gibt mir das Problem, dass, wenn ich aus Group0 entferne, ich auch aus Klon entfernen. Wie kann ich das überwinden? Wie erstelle ich eine unabhängige Kopie von group0? – Hristo

Antwort

7

Andere haben die richtige Lösung erwähnt, ohne sie zu formulieren. Also hier ist es:

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

Auch, wenn Sie sicher wollen, um die Karte in Ihrer assign Funktion zu ändern, müssen Sie in der Iterator passieren (von denen Sie nur die Funktion remove und nur einmal verwenden kann) oder die Eintrag um den Wert zu ändern.

+0

Danke ... das ist genau was ich suche! – Hristo

0

Sie müssen den tatsächlichen Iterator und seine remove-Methode verwenden, wenn Sie die Auflistung ändern möchten, während Sie sie durchlaufen. Mit dem foreach-Konstrukt gibt es eigentlich keine Möglichkeit.

Wenn Sie versuchen, mehrere Einträge in einer Iteration zu entfernen, müssen Sie eine Schleife über etwas erstellen, das nicht von der Map unterstützt wird.

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()' kann möglicherweise auch mehr als 1 Elemente aus group0 entfernen ... so gibt es die Chance, dass eine Iteration alle Elemente in group0 entfernt und keine zweite Iteration benötigt. Können Sie Code für die Funktionsweise des Iterators eingeben? – Hristo

0

In diesem Fall, wie assign kann group0 ändern? Weitere Details sind erforderlich. Normalerweise können Sie eine Sammlung nicht ändern, während Sie darüber iterieren. Sie ändern über die Schnittstelle Iterator.

1
+0

.. interessant. Danke für den Vorschlag. Könnten Sie kurz auf die Leistungsvorteile einer ConcurrentHashMap eingehen? Gibt es signifikante Verbesserungen bei der Verwendung einer solchen Datenstruktur hinsichtlich der Überprüfung, ob ein Element existiert, ein Element erhalten, ein Element entfernen, ein Element einfügen usw.? – Hristo

1

In Ihrem speziellen Fall würde ich die Struktur der HashMap nicht ändern, sondern nur den Wert null, den Sie entfernen möchten. Wenn Sie dann einen Nullwert besuchen, überspringen Sie ihn einfach.

Im allgemeinen Fall bevorzuge ich einen Stack für solche Dinge, da sie besonders einfach zu visualisieren sind und ich daher weniger Probleme mit den Randbedingungen habe (einfach nur 'popping' bis 'leer').

+0

ahh ... gute Idee :) aber die Verwendung eines Stacks ist hier völlig falsch ... wenn ich zum Beispiel prüfen wollte, ob ein Element existiert, wäre das hier lächerlich ineffizient. Für mein Ziel ist Effizienz und Geschwindigkeit ein Muss. aber ich mag die Idee des Nullwerdens. +1 – Hristo

Verwandte Themen