Wednesday, December 20, 2006

Como borrar elementos de una lista generica

El codigo para este articulo aplica a C# 2.0

Una tarea mas o menos comun cuando usamos una lista generica, es borrar elementos de esta, vamos a ver que alternativas tenemos:

#1 La forma definitivamente equivocada de hacerlo:

List<Person> l1 = GetList();
//*** The wrong way
foreach (Person p in l1) {
if (p.Age > 30)
l1.Remove(p);
}

Este codigo nos dara una excepcion InvalidOperationException: "Collection was modified; enumeration operation may not execute."

#2 Funciona mas o menos (y nos permite ejecutar una accion en cada elemento que vamos a borrar)

List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
ints.Add(5);
ints.Add(6);

ints.ForEach(delegate(int i) {
if ((i % 2) == 0) {
Console.WriteLine("removing"+i.ToString());
ints.Remove(i);
}
});

Si corres este codigo funcionara perfectamente, pero la verdad es que tiene un problema grande, si agregaras los numeros pares primero, verias que no los borra todos, y no te da una excepcion ni nada, simplemente se sale del foreach y continua; asi que este metodo funciona, pero solo en condiciones especiales, lo cual lo hace codigo peligroso

#3 La forma correcta: recorremos la coleccion hacia atras y borramos elementos cuando necesitamos
int x = ints2.Count;
while (--x>=0) {
if (ints2[x] < 4)
ints2.RemoveAt(x);
}

#4 Una mejor manera: La lista generica trae un metodo ya incluido que nos sirve para borrar multiples elementos

ints2.RemoveAll(delegate(int i) {
return i <4;
});

#5 Pero que pasa si quiero ejecutar una accion en cada elemento que se borre?

ints2.RemoveAll(delegate(int i) {
if (i < 4) {
//*** Perform action here
Console.WriteLine("removing :" + i.ToString());
return true;
}
else
return false;
});


Si el elemento fuera una clase, podrias mandar llamar uno de sus metodos antes de borrarlo (por ejemplo una llamada a la base de datos)

Mas adelante escribire en detalle porque exactamente las alternativas #1 y #2 no funcionan

salu2

No comments: