2010-08-18 9 views
5

Possible Duplicates:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over itCome posso scorrere su un oggetto mentre lo si modifica in Java?

sto cercando di collegare attraverso HashMap:

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

... ed estrarre ogni elemento in group0. Questo è il mio approccio:

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

Il problema qui è che ogni chiamata a assign() rimuoverà gli elementi da group0, modificando così la sua dimensione, causando in tal modo il seguente errore:

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) 

Allora ... come posso scorrere gli elementi in group0 mentre cambia dinamicamente?

+2

Creare una copia della mappa group0 e rimuovere elementi dalla copia durante il looping del gruppo0? – sarahTheButterFly

+0

@sarah ... buon punto. Ci proverò. – Hristo

+0

@sarah ...copiare su group0 su un clone HashMap mi dà il problema che quando rimuovo dal gruppo0, rimuovo anche da clone. Come posso superarlo? Come posso creare una copia indipendente di group0? – Hristo

risposta

7

Altri hanno menzionato la soluzione corretta senza spelling. Così qui è:

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

Inoltre, se si desidera modificare in modo sicuro la mappa nella funzione di assegnazione, è necessario passare l'iteratore (di cui è possibile utilizzare solo la funzione di rimozione e solo una volta) o la voce per modificare il valore.

+0

Grazie ... questo è esattamente quello che sto cercando! – Hristo

0

È necessario utilizzare l'iteratore effettivo e il relativo metodo di rimozione se si desidera modificare la raccolta mentre si esegue il ciclo su di essa. Non c'è davvero alcun modo di farlo con il costrutto foreach.

Se si sta tentando di rimuovere più voci in un'unica iterazione, è necessario eseguire il loop su qualcosa che non è supportato dalla mappa.

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()' può anche rimuovere potenzialmente più di 1 elementi dal gruppo0 ... quindi c'è la possibilità che una iterazione rimuova tutti gli elementi in group0 e non sia necessario per una seconda iterazione. Puoi pubblicare il codice per come funziona Iterator? – Hristo

0

In questo caso, come si può modificare assigngroup0? Maggiori dettagli sono necessari. In genere non è possibile modificare una raccolta durante l'iterazione su di essa. Si modifica tramite l'interfaccia Iterator.

1
+0

.. interessante. Grazie per il suggerimento. Potresti toccare brevemente i vantaggi prestazionali dell'utilizzo di ConcurrentHashMap? Ci sono miglioramenti significativi nell'utilizzo di tale struttura dati, in termini di controllo se esiste un elemento, ottenendo un elemento, rimuovendo un elemento, inserendo un elemento, ecc ...? – Hristo

1

Nel tuo caso particolare non modifico la struttura di HashMap ma semplicemente annullo il valore che vuoi rimuovere. Quindi se si finisce per visitare un valore nullo, basta saltarlo.

Nel caso generale, preferisco utilizzare una pila per cose come questa perché sono particolarmente facili da visualizzare e quindi tendo ad avere meno problemi con le condizioni di confine (continuando a scoccare fino allo svuotamento).

+0

ahh ... buona idea :) ma usare uno stack è completamente errato qui ... per esempio se volessi controllare se un elemento esiste, sarebbe ridicolmente inefficiente qui. Per il mio obiettivo, l'efficienza e la velocità sono un must. ma mi piace l'idea di nullare. +1 – Hristo

Problemi correlati