vaciar una ultimo todos toda nodo los lista enlazada eliminar elementos elemento como buscar borrar aƱadir c# list foreach enumeration

c# - todos - eliminar ultimo nodo de una lista c++



Manera inteligente de eliminar elementos de una lista<T> al enumerar en C# (8)

A medida que enumera la lista, agregue la que desea MANTENER a una nueva lista. Después, asigne la nueva lista a myIntCollection

List<int> myIntCollection=new List<int>(); myIntCollection.Add(42); List<int> newCollection=new List<int>(myIntCollection.Count); foreach(int i in myIntCollection) { if (i want to delete this) /// else newCollection.Add(i); } myIntCollection = newCollection;

Tengo el caso clásico de tratar de eliminar un elemento de una colección al enumerarlo en un bucle:

List<int> myIntCollection = new List<int>(); myIntCollection.Add(42); myIntCollection.Add(12); myIntCollection.Add(96); myIntCollection.Add(25); foreach (int i in myIntCollection) { if (i == 42) myIntCollection.Remove(96); // The error is here. if (i == 25) myIntCollection.Remove(42); // The error is here. }

Al comienzo de la iteración después de que se produce un cambio, se lanza una InvalidOperationException , porque a los enumeradores no les gusta cuando cambia la colección subyacente.

Necesito hacer cambios en la colección mientras realizo la iteración. Hay muchos patrones que pueden usarse para evitar esto , pero ninguno de ellos parece tener una buena solución:

  1. No elimine dentro de este ciclo, en su lugar mantenga una "Lista de eliminación" por separado, que procese después del ciclo principal.

    Normalmente, esta es una buena solución, pero en mi caso, necesito que el elemento desaparezca al instante como "esperar" hasta que después del ciclo principal para realmente eliminar el elemento cambie el flujo lógico de mi código.

  2. En lugar de eliminar el elemento, simplemente establece un indicador en el elemento y márcalo como inactivo. A continuación, agregue la funcionalidad del patrón 1 para limpiar la lista.

    Esto funcionaría para todas mis necesidades, pero significa que una gran cantidad de código tendrá que cambiar para verificar el indicador inactivo cada vez que se accede a un elemento. Esto es demasiada administración para mi gusto.

  3. De alguna manera, incorpore las ideas del patrón 2 en una clase que se deriva de List<T> . Esta Superlista manejará la bandera inactiva, la eliminación de objetos después del hecho y tampoco expondrá los elementos marcados como inactivos para los consumidores de enumeración. Básicamente, simplemente encapsula todas las ideas del patrón 2 (y, posteriormente, el patrón 1).

    ¿Existe una clase como esta? ¿Alguien tiene código para esto? ¿O hay un mejor camino?

  4. Me han dicho que el acceso a myIntCollection.ToArray() lugar de myIntCollection resolverá el problema y me permitirá eliminarlo dentro del ciclo.

    Esto me parece un mal patrón de diseño, ¿o tal vez está bien?

Detalles:

  • La lista contendrá muchos elementos y solo eliminaré algunos de ellos.

  • Dentro del ciclo, haré todo tipo de procesos, agregando, eliminando etc., por lo que la solución debe ser bastante genérica.

  • El ítem que necesito eliminar puede no ser el ítem actual en el ciclo. Por ejemplo, puedo estar en el elemento 10 de un ciclo de 30 elementos y necesito eliminar el elemento 6 o el elemento 26. Caminar hacia atrás a través de la matriz ya no funcionará debido a esto. ; o (


Cuando necesite iterar a través de una lista y pueda modificarla durante el ciclo, entonces es mejor utilizar un ciclo for:

for (int i = 0; i < myIntCollection.Count; i++) { if (myIntCollection[i] == 42) { myIntCollection.Remove(i); i--; } }

Por supuesto, debe tener cuidado, por ejemplo, disminuyo i cada vez que se elimina un elemento, de lo contrario omitiremos las entradas (una alternativa es ir hacia atrás a través de la lista).

Si tiene Linq entonces debería usar RemoveAll como dlev ha sugerido.


La mejor solución suele ser utilizar el método RemoveAll() :

myList.RemoveAll(x => x.SomeProp == "SomeValue");

O bien, si necesita eliminar ciertos elementos:

MyListType[] elems = new[] { elem1, elem2 }; myList.RemoveAll(x => elems.Contains(x));

Esto supone que su bucle está destinado únicamente para la eliminación, por supuesto. Si necesita un procesamiento adicional, entonces el mejor método suele ser utilizar un ciclo for o while, ya que no está utilizando un enumerador:

for (int i = myList.Count - 1; i >= 0; i--) { // Do processing here, then... if (shouldRemoveCondition) { myList.RemoveAt(i); } }

Retroceder asegura que no se salte ningún elemento.

Respuesta a Editar :

Si va a eliminar elementos aparentemente arbitrarios, el método más fácil podría ser realizar un seguimiento de los elementos que desea eliminar y luego eliminarlos todos a la vez. Algo como esto:

List<int> toRemove = new List<int>(); foreach (var elem in myList) { // Do some stuff // Check for removal if (needToRemoveAnElement) { toRemove.Add(elem); } } // Remove everything here myList.RemoveAll(x => toRemove.Contains(x));


Qué tal si

int[] tmp = new int[myIntCollection.Count ()]; myIntCollection.CopyTo(tmp); foreach(int i in tmp) { myIntCollection.Remove(42); //The error is no longer here. }


Sé que esta publicación es antigua, pero pensé que compartiría lo que funcionó para mí.

Cree una copia de la lista para enumerar, y luego en cada bucle, puede procesar los valores copiados y eliminar / agregar / lo que sea con la lista fuente.

Private Sub RemoveMyObjectsFromMyList(MyList As List(Of MyObject)) For Each obj As MyObject In MyList.ToList If obj.DeterminingValue > 10 Then MyList.Remove(obj) End If Next End Sub

Mi respuesta está en vb.net pero el concepto es el mismo


Si ambos deben enumerar una List<T> y eliminarla, sugiero simplemente usar un ciclo while en lugar de un foreach

var index = 0; while (index < myList.Count) { if (someCondition(myList[index])) { myList.RemoveAt(index); } else { index++; } }


Si está interesado en un alto rendimiento, puede usar dos listas. Lo siguiente minimiza la recolección de basura, maximiza la ubicación de la memoria y nunca elimina realmente un elemento de una lista, lo cual es muy ineficiente si no es el último elemento.

private void RemoveItems() { _newList.Clear(); foreach (var item in _list) { item.Process(); if (!item.NeedsRemoving()) _newList.Add(item); } var swap = _list; _list = _newList; _newList = swap; }


Vamos a agregar tu código:

List<int> myIntCollection=new List<int>(); myIntCollection.Add(42); myIntCollection.Add(12); myIntCollection.Add(96); myIntCollection.Add(25);

Si desea cambiar la lista mientras está en un foreach, debe escribir .ToList()

foreach(int i in myIntCollection.ToList()) { if (i == 42) myIntCollection.Remove(96); if (i == 25) myIntCollection.Remove(42); }