for example collection array c# collections iteration

c# - example - iterator java



Cómo modificar o eliminar elementos de una colección enumerable mientras se itera en C# (8)

Tengo que eliminar algunas filas de una tabla de datos. He oído que no está bien cambiar una colección mientras la repito. Entonces, en lugar de un bucle for en el que verifico si una fila cumple con las demandas de eliminación y luego marcarla como eliminada, primero debo iterar a través de la tabla de datos y agregar todas las filas en una lista, luego recorrer la lista y marcar las filas para las eliminaciones ¿Cuáles son las razones para esto, y qué alternativas tengo (en lugar de utilizar la lista de filas quiero decir)?


Cuando necesito eliminar un elemento de una colección que estoy enumerando, generalmente lo enumero al revés.


Dado que está trabajando con una DataTable y necesita poder realizar cambios en el servidor con un adaptador de tabla (consulte los comentarios), aquí hay un ejemplo de cómo debe eliminar las filas:

DataTable dt; // remove all rows where the last name starts with "B" foreach (DataRow row in dt.Rows) { if (row["LASTNAME"].ToString().StartsWith("B")) { // mark the row for deletion: row.Delete(); } }

Al llamar a eliminar en las filas, se cambiará su propiedad RowState a Deleted, pero se dejarán las filas eliminadas en la tabla. Si aún necesita trabajar con esta tabla antes de continuar con los cambios en el servidor (por ejemplo, si desea mostrar el contenido de la tabla menos las filas eliminadas), debe verificar el RowState de cada fila mientras lo itera de esta manera. :

foreach (DataRow row in dt.Rows) { if (row.RowState != DataRowState.Deleted) { // this row has not been deleted - go ahead and show it } }

La eliminación de filas de la colección (como en la respuesta de Bruno) romperá el adaptador de la tabla, y generalmente no debería hacerse con una DataTable.


Eliminar o agregar a la lista mientras se itera puede romperla, como dijiste.

A menudo utilicé un enfoque de dos listas para resolver el problema:

ArrayList matches = new ArrayList(); //second list for MyObject obj in my_list { if (obj.property == value_i_care_about) matches.addLast(obj); } //now modify for MyObject m in matches { my_list.remove(m); //use second list to delete from first list } //finished.


Iterar al revés a través de la lista suena como un mejor enfoque, porque si quitas un elemento y otros elementos "caen en la brecha", eso no importa porque ya los has examinado. Además, no tiene que preocuparse de que su variable contraria se vuelva más grande que .Count.

List<int> test = new List<int>(); test.Add(1); test.Add(2); test.Add(3); test.Add(4); test.Add(5); test.Add(6); test.Add(7); test.Add(8); for (int i = test.Count-1; i > -1; i--) { if(someCondition){ test.RemoveAt(i); } }


La solución de chakrit también se puede usar si estás apuntando a .NET 2.0 (sin expresiones LINQ / lambda) usando un delegado en lugar de una expresión lambda:

public bool IsMatch(int item) { return (item % 3 == 1); // put whatever condition you want here } public void RemoveMatching() { List<int> x = new List<int>(); x.RemoveAll(new Predicate<int>(IsMatch)); }


Tomando el código @bruno, lo haría al revés.

Porque cuando retrocede, los índices de matriz faltantes no interfieren con el orden de su ciclo.

var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 }); for (int i = l.Count - 1; i >= 0; i--) if (l[i] % 2 == 0) l.RemoveAt(i); foreach (var i in l) { Console.WriteLine(i); }

Pero seriamente, estos días, usaría LINQ:

var l = new List<int>(new int[] { 0, 1, 2, 3, 4, 5, 6 }); l.RemoveAll(n => n % 2 == 0);


Un ciclo while manejaría esto:

int i = 0; while(i < list.Count) { if(<codition for removing element met>) { list.RemoveAt(i); } else { i++; } }


Puede eliminar elementos de una colección si usa un bucle for simple.

Echale un vistazo a éste ejemplo:

var l = new List<int>(); l.Add(0); l.Add(1); l.Add(2); l.Add(3); l.Add(4); l.Add(5); l.Add(6); for (int i = 0; i < l.Count; i++) { if (l[i] % 2 == 0) { l.RemoveAt(i); i--; } } foreach (var i in l) { Console.WriteLine(i); }