2010-08-18 8 views
5

Possible Duplicates:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over it¿Cómo puedo iterar sobre un objeto mientras lo modifico en Java?

estoy tratando de bucle a través de HashMap:

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

... y extraer todos los elementos de group0. Este es mi enfoque:

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

El problema aquí es que cada llamada a assign() eliminará los elementos de group0, modificando así su tamaño, lo que provoca el error siguiente:

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) 

Entonces ... ¿cómo ¿Puedo recorrer los elementos en group0 mientras está cambiando dinámicamente?

+2

Haga una copia del mapa group0 y elimine los elementos de la copia mientras recorre el grupo0? – sarahTheButterFly

+0

@sarah ... buen punto. Voy a intentar eso. – Hristo

+0

@sarah ...copiar sobre group0 a un clon HashMap me da el problema que cuando elimino del group0, también lo remuevo del clon. ¿Cómo puedo superar eso? ¿Cómo hago una copia independiente de group0? – Hristo

Respuesta

7

Otros han mencionado la solución correcta sin realmente deletrearla. Así que aquí está:

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

Además, si desea cambiar de forma segura el mapa en su función de asignación, que necesita para pasar del iterador (de los cuales sólo se puede utilizar la función de eliminación y sólo una vez) o la entrada para cambiar el valor.

+0

Gracias ... ¡esto es exactamente lo que estoy buscando! – Hristo

0

Debe utilizar el iterador real y su método de eliminación si desea modificar la colección mientras se repite sobre ella. Realmente no hay forma de hacerlo con la construcción foreach.

Si está intentando eliminar varias entradas en una iteración, tendrá que recorrer algo que no esté respaldado por el mapa.

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()' también puede eliminar más de 1 elementos del grupo0 ... por lo que existe la posibilidad de que una iteración elimine todos los elementos en group0 y no necesite una segunda iteración. ¿Puedes publicar el código de cómo funciona el iterador? – Hristo

0

En este caso, ¿cómo se puede modificar assigngroup0? Se necesitan más detalles. Normalmente no se puede modificar una colección mientras se itera sobre ella. Usted modifica a través de la interfaz Iterator.

1
+0

.. interesante. Gracias por la sugerencia. ¿Podría tocar brevemente los beneficios de rendimiento de usar un ConcurrentHashMap? ¿Hay mejoras significativas en el uso de dicha estructura de datos, en términos de verificar si un elemento existe, obtener un elemento, eliminar un elemento, insertar un elemento, etc.? – Hristo

1

En su caso particular, no modificaría la estructura de HashMap, sino que simplemente anularía el valor que desea eliminar. Entonces, si termina visitando un valor nulo, sáltelo.

En el caso general, prefiero usar una pila para este tipo de cosas porque son particularmente fáciles de visualizar y por eso tiendo a tener menos problemas con las condiciones fronterizas (simplemente mantengo el popping 'hasta que quede vacío).

+0

ahh ... buena idea :) pero usar una pila es completamente incorrecto aquí ... por ejemplo, si quisiera verificar si existe un elemento, sería ridículamente ineficiente aquí. Para mi objetivo, la eficiencia y la velocidad son obligatorias. pero me gusta la idea de anular. +1 – Hristo

Cuestiones relacionadas