2010-04-30 35 views
126

Estoy intentando descubrir cómo recorrer una lista genérica de elementos que deseo eliminar de otra lista de elementos.Eliminar elementos de una lista en otra

Así que vamos a decir que tienen esto como un ejemplo hipotético

List<car> list1 = GetTheList(); 
List<car> list2 = GetSomeOtherList(); 

Quiero atravesar lista1 con un foreach y quitar cada elemento de Lista1 que también está contenida en Lista2.

No estoy muy seguro de cómo hacerlo ya que foreach no se basa en índices.

+1

Quiere eliminar elementos en Lista1 que también están en Lista2? –

+0

Necesita eliminar elementos de list1 y agregarlos a list2 u otra cosa? – danish

+0

Relacionado: http://stackoverflow.com/questions/2477633/a-question-about-comparing-listt –

Respuesta

246

Puede utilizar Except:

List<car> list1 = GetTheList(); 
List<car> list2 = GetSomeOtherList(); 
List<car> result = list2.Except(list1).ToList(); 

Es probable que ni siquiera necesita esas variables temporales:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList(); 

Tenga en cuenta que Except no modifica ninguna de las listas - crea un nuevo lista con el resultado

+8

Punto menor, pero esto producirá un 'IEnumerable ', no una 'List '. Debes llamar a 'ToList()' para recuperar una lista. Además, creo que debería ser 'GetSomeOtherList(). Excepto (GetTheList()). ToList()' –

+5

También necesitará 'using System.Linq;' si no lo tenía antes. – yellavon

+0

He agregado el uso de System.Linq pero todavía no puedo acceder a Except. Pero en mi caso estoy usando ArrayList. ¿Alguna idea sobre cómo hacer que funcione con ArrayList? – BKSpurgeon

23

No necesita un índice, ya que la clase List<T> le permite eliminar elementos por valor en lugar de índice utilizando la función Remove.

foreach(car item in list1) list2.Remove(item); 
+1

+1, pero IMO debería usar corchetes alrededor de la declaración 'list2.Remove (item);'. – ANeves

+2

@sr pt: siempre utilizo corchetes en las sentencias que aparecen en otra línea, pero no en los bloques de una sola declaración que puedo/hago en la misma línea que la sentencia de control de flujo. –

+0

Siempre y cuando sea coherente, no importa si usa corchetes o no .. IMO :) –

21

Recomendaría usar el LINQ extension methods. Se puede hacer fácilmente con una línea de código, así:

list2 = list2.Except(list1).ToList(); 

Esto es suponiendo, por supuesto, los objetos de list1 que va a quitar de lista2 son la misma instancia.

+1

También elimina duplicados. –

-4

Aquí ya go ..

List<string> list = new List<string>() { "1", "2", "3" }; 
    List<string> remove = new List<string>() { "2" }; 

    list.ForEach(s => 
     { 
      if (remove.Contains(s)) 
      { 
       list.Remove(s); 
      } 
     }); 
+3

-1. Esto lanzará una excepción después de que se elimine el primer elemento. Además, es (generalmente) una mejor idea atravesar la lista para * eliminar *, ya que generalmente es más pequeño. También estás forzando más cruces de listas haciéndolo de esta manera. –

10

Se podría utilizar LINQ, pero me gustaría ir con RemoveAll método. Creo que es el que mejor expresa tu intención.

var integers = new List<int> { 1, 2, 3, 4, 5 }; 

var remove = new List<int> { 1, 3, 5 }; 

integers.RemoveAll(i => remove.Contains(i)); 
+7

O incluso más simple con grupos de métodos que puedes hacer - enteros.RemoveAll (remove.Contains); – Ryan

4

Solución 1: Se puede hacer así:

List<car> result = GetSomeOtherList().Except(GetTheList()).ToList(); 

embargo, en algunos casos puede que esta solución no funciona. si no funciona, puede usar mi segunda solución.

Solución 2:

List<car> list1 = GetTheList(); 
List<car> list2 = GetSomeOtherList(); 

pretendemos que lista1 es la lista principal y lista2 es su lista de secondry y desea obtener los elementos de lista1 sin elementos de lista2.

var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList(); 
8

En mi caso tenía dos listas diferentes, con un identificador común, algo así como una clave externa. La segunda solución citada por "nzrytmn":

var result = list1.Where(p => !list2.Any(x => x.ID == p.ID && x.property1 == p.property1)).ToList(); 

fue el que mejor ajuste en mi situación. Necesitaba cargar una DropDownList sin los registros que ya se habían registrado.

Gracias!

Este es mi código:

t1 = new T1(); 
t2 = new T2(); 

List<T1> list1 = t1.getList(); 
List<T2> list2 = t2.getList(); 

ddlT3.DataSource= list2.Where(s => !list1.Any(p => p.Id == s.ID)).ToList(); 
ddlT3.DataTextField = "AnyThing"; 
ddlT3.DataValueField = "IdAnyThing"; 
ddlT3.DataBind(); 
3
list1.RemoveAll(l => list2.Contains(l)); 
+0

a.k.a. "totalmente impuro" :-) –

Cuestiones relacionadas