Introducción
Existen muchas formas de trabajar con una lista, y realizar operaciones de búsqueda y eliminación de aquellos elementos que debe ser filtrados, pero hay que tener cuidado ya que no todas las operaciones son validas
En este articulo se analizaría las formas de buscar un elemento y removerlo de la colección, analizando además métodos no recomendados
El problema
Cuando se tiene que realizar una operación sobre una lista, filtrando sus datos, lo primero que viene a la mente es recorrerla y allí mismo eliminar los ítems que no coinciden con la búsqueda.
O sea implementar algo similar a esto:
private void btnEliminarConProblema_Click(object sender, EventArgs e) { List<Producto> list = ObtenerLista(); foreach (Producto item in list) { if (!item.Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower())) list.Remove(item); } LoadListView(list); }
Pero esta primera aproximación presenta un defecto técnico, resulta que las listas necesita mantener el índice intacto para poder mantener el ciclo, el cual estamos alterando si removemos un ítem.
En este caso veremos un error con el mensaje:
Collection was modified; enumeration operation may not execute.
Soluciones
Existe una buen variedad de soluciones a este problema, en donde la implementación de cada una dependerá del objetivo que se quiera alcanzar
Una de ellas podría ser implementando el ciclo por medio de un simple for
[Usando el For]
private void btnEliminarConFor_Click(object sender, EventArgs e) { List<Producto> list = ObtenerLista(); for (int i = 0; i < list.Count; i++) { if (!list[i].Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower())) { list.RemoveAt(i); i--; } } LoadListView(list); }
Como se observa este requiere trabar con los índices de la colección, pero para poder mantenerlo actualizado es preciso restar uno cuando un ítem es quitado.
Otra alternativa podrías ser usar una lista auxiliar que acumule los ítems que no coinciden con la búsqueda, para ser eliminado en un segundo ciclo de la lista
[Usando una lista auxiliar]
private void btnEliminarConColeccionAuxiliar_Click(object sender, EventArgs e) { List<Producto> listAux = new List<Producto>(); List<Producto> list = ObtenerLista(); foreach (Producto item in list) { if (!item.Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower())) { listAux.Add(item); continue; } } foreach (Producto item in listAux) { list.Remove(item); } LoadListView(list); }
El inconveniente con esta aproximación es que se necesitan dos ciclos para terminar la tarea.
También existen alternativas algo mas performantes, como ser el uso de delegados, expresiones Lambda, o Linq
[Usando Delegados]
private void btnEliminarConDelegate_Click(object sender, EventArgs e) { List<Producto> list = ObtenerLista(); // // quitara aquellos productos en donde la funcion // definida en el delegado retorne un true // list.RemoveAll(delegate(Producto prod) { return !prod.Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower()); }); LoadListView(list); }
[Usando Expresiones Lambda]
private void btnEliminarConLambda_Click(object sender, EventArgs e) { List<Producto> list = ObtenerLista(); list.RemoveAll(x => !x.Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower())); LoadListView(list); }
[Usando Linq]
private void btnEliminarConLinq_Click(object sender, EventArgs e) { List<Producto> list = ObtenerLista(); list = (from item in list where item.Descripcion.ToLower().Contains(txtBusqueda.Text.ToLower()) select item).ToList<Producto>(); LoadListView(list); }
[C#]
|
[VB.NET]
|
Gracias Leandro, me he topado con tus ayudas en toda la red, es un gran trabajo el que realizas, otra vez una ayuda tuya me soluciona un problema.
ResponderEliminarGracias otra vez y saludos desde Perú!!
Saludos Leandro
ResponderEliminarTengo una lista y deseo poder eliminar un elemento algoi así como
var upd = DT1 .Where (c => c.id == myId).Update (d => d.nombre = otroNombre) ;
Gracias desde ya
David
hola Carlos
ResponderEliminarsi la idea es usa lambda porque no usas
DT1.RemoveAll(c=>c.id == myId)
con eso remueves los items que coincidan con la comparacion
saludos
Hola leandro, tu código me parece excelente, estoy haciendo algo similar a tu código pero no encuentro la sintaxis correcta y talvez me puedes ayudar, tengo un dataset con 2 columnas una contiene el nombre de un archivo y la otra la ruta del archivo, ya tengo el bucle para extraer todas las rutas del dataset en string[], ahora lo que necesito es iterar en este array y comprobar que todos los archivos existen, en caso de que no exista me elimine la fila en el dataset de los archivos que no encuentre....
ResponderEliminarMuchas gracias de antemano
Estoy usando C#
ResponderEliminarEste comentario ha sido eliminado por el autor.
ResponderEliminarHola Leandro,
ResponderEliminartus posts me ayudaron con todo lo que necesite! muy buenos aportes!
Te queria consultar algo.
Tengo un Gridview cargado con items de textboxs y quisiera eliminar uno solo o varios con Checkboxes que ya tengo en el gridview.
protected void Borrar_Click(object sender, ImageClickEventArgs e)
{
foreach (GridViewRow item in grdArticulos.Rows)
{
System.Web.UI.WebControls.CheckBox chk = (System.Web.UI.WebControls.CheckBox)item.FindControl("chkDelete");
if (chk != null)
{
if (chk.Checked)
{
DialogResult result;
//result = MessageBox.Show(message, caption, buttons);
result = MessageBox.Show("Desea eliminar el articulo?", "Advertencia", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
if (result == System.Windows.Forms.DialogResult.No)
{
return;
}
else
{
//ACA DEBERIA BORRARLO, PERO NO SE HACERLO
}
}
}
}
}
espero puedas ayudarme!
Gracias!
Hola buenas tardes, me he topado con un caso similar, pero en vez de eliminar , lo que quiero es añadir un registro a la colección, lo intente de la manera similar como el que muestras, y si me los aggrega pero al llegar al final me marco el error de que la coleccion ha sido editada y no deja continuar, no se si pude explicarme correctamente.
ResponderEliminarhola
EliminarEs que tanto para agregar o eliminar no puedes hacerlo en la lista o coleccion que estas iterando en el foreach, requieres de una lista auxiliar donde ir agregando y al final recorres esta lista auxiliar y agregas los items en la lista definitiva
saludos
Este comentario ha sido eliminado por el autor.
EliminarEste comentario ha sido eliminado por el autor.
ResponderEliminarMuchísimas gracias. Sin tu ayuda no hubiese comprendido que el error provenía de borrar un elemento de una lista en un foreach. Opté por eso hacerlo fuera de la siguiente manera:
ResponderEliminarbool remover = false;
Tipo borrarElemento = new Tipo();
foreach (Tipo elemento in Lista)
{
if (elemento == elementoBuscado)
{
borrarElemento = elemento;
remover = true;
}
}
if (remover)
{
Lista.Remove(borrarElemento);
}
Nuevamente gracias por tu ayuda. Un saludo.