.net design-patterns ienumerable

.net - Cómo eliminar objetos de una colección Enumerable en un bucle



design-patterns ienumerable (7)

Duplicar

Modificar una colección mientras se itera a través de ella

Alguien tiene un patrón agradable que me permita esquivar la incapacidad de eliminar objetos mientras recorro una colección enumerable (por ejemplo, un IList o KeyValuePairs en un diccionario)

Por ejemplo, el siguiente error, ya que modifica la Lista que se enumera durante el foreach

foreach (MyObject myObject in MyListOfMyObjects) { if (condition) MyListOfMyObjects.Remove(myObject); }

En el pasado, he usado dos métodos.

He reemplazado el foreach con un ciclo for invertido (para no cambiar los índices sobre los que estoy haciendo un bucle si elimino un objeto).

También intenté almacenar una nueva colección de objetos para eliminarlos dentro de un ciclo, luego recorrí esa colección y eliminé los objetos de la colección original.

Funcionan bien, pero ninguno se siente bien, y me preguntaba si alguien ha encontrado una solución más elegante al problema.



Haz lo inverso, creando una nueva lista:

List myFilteredList = new List(); foreach (MyObject myObject in myListOfMyObjects) { if (!condition) myFilteredList.Add(myObject); }

Luego usa la nueva lista donde sea que la necesites.

También puede usar una expresión LINQ fácilmente, de nuevo, invirtiendo la condición. Esto tiene el beneficio adicional de no crear una nueva estructura, sino también las dificultades de ser un enumerable perezoso:

var myFilteredList = from myObject in myListOfMyObjects where !condition select myObject;

Sin embargo, si realmente necesita eliminar los elementos de la lista, normalmente uso el enfoque "crear una nueva lista, luego reiterar y eliminar".


No me gusta la idea del bucle invertido, ya que solo funciona en ciertas estructuras de datos.

En general, utilizaría la segunda técnica y acumularía los elementos que se eliminarán en una colección separada ''a ser eliminada''. Si la eliminación puede hacer que los iterates existentes se invaliden (como sucederá con cualquier colección de árbol equilibrada, por ejemplo), entonces no veo una forma de evitar esto.

La única otra técnica que he usado ocasionalmente es reiniciar toda la iteración cuando encuentre el primer elemento para eliminar. Si lo hace sin encontrar ningún elemento para eliminar, entonces la función ha finalizado. Esto es ineficiente, pero a veces es necesario si eliminar un elemento de la colección puede cambiar el conjunto de elementos que deben eliminarse.


Es bastante simple, pero cuando planeo eliminar elementos de un IEnumerable / IList, por lo general solo hago una copia:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects)) { if (condition) MyListOfMyObjects.Remove(myObject); }

No es la forma más eficiente de hacerlo, pero es fácil de leer. Optimización prematura y todo eso.


Acabo de encontrar esta publicación y pensé que compartiría.

void RemoveAll(object condition) { bool found = false; foreach(object thisObject in objects) { if (condition) { objects.Remove(thisObject); found = true; break; //exit loop } } // Call again recursively if (found) RemoveAll(condition); }


Tengo un diccionario y quiero deshacerme de todos los valores. Cuando se elimina cada valor, se elimina del diccionario que crea el problema que usted discute. Hice lo siguiente:

foreach (var o in dictionary.Values.ToList()) { o.Dispose(); }


Aprecio que esto puede estar muerto ahora, pero la forma en que siempre hago esto es:

foreach (MyObject myObject en MyListOfMyObjects)
{

if (condición) MyListOfMyObjects.Remove (myObject);

descanso;

}

El objeto se elimina y luego sale el bucle, ¡viola!