2010-04-30 20 views
126

Sto cercando di capire come attraversare un elenco generico di elementi che voglio rimuovere da un altro elenco di elementi.Rimuovi elementi da un elenco in un altro

Quindi diciamo che ho questo come un esempio ipotetico

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

voglio attraversare list1 con un foreach e rimuovere ogni elemento di Lista1 che è anche contenuta in List2.

Non sono abbastanza sicuro su come procedere perché foreach non è basato su indice.

+1

Si desidera rimuovere elementi in Lista1, che sono anche in List2? –

+0

È necessario rimuovere elementi da list1 e aggiungerli a list2 o qualcos'altro? – danish

+0

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

risposta

246

È possibile utilizzare Except:

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

Probabilmente non hai nemmeno bisogno di quelle variabili temporanee:

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

noti che Except non modifica nessuna delle due liste - crea un nuovo lista con il risultato.

+8

Punto minore, ma questo produrrà un 'IEnumerable ', non un 'Elenco '. Devi richiamare 'ToList()' per recuperare una lista. Inoltre, credo che dovrebbe essere 'GetSomeOtherList(). Tranne (GetTheList()). ToList()' –

+5

Devi anche usare 'System.Linq;' se non lo avevi prima. – yellavon

+0

Ho aggiunto utilizzando System.Linq ma non riesco ancora ad accedere Tranne. Ma nel mio caso sto usando ArrayList. Qualche idea su come farlo funzionare con ArrayList? – BKSpurgeon

23

Non è necessario un indice, in quanto la classe List<T> consente di rimuovere gli articoli per valore anziché per indice utilizzando la funzione Remove.

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

+1, ma IMO dovresti usare parentesi attorno alla dichiarazione 'list2.Remove (elemento);'. – ANeves

+2

@sr pt: Uso sempre le parentesi su istruzioni che appaiono su un'altra riga, ma non su blocchi a singola istruzione che posso/fare posto sulla stessa riga dell'istruzione di controllo di flusso. –

+0

Fintanto che sei coerente, non importa se usi parentesi o meno .. IMO :) –

21

Si consiglia di utilizzare LINQ extension methods. Si può facilmente farlo con una sola riga di codice in questo modo:

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

Ciò presuppone, naturalmente, gli oggetti in lista1 che si sta rimuovendo dal lista2 sono la stessa istanza.

+1

Rimuove anche i duplicati. –

-4

Qui 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. Ciò genererà un'eccezione dopo che il primo elemento è stato rimosso. Inoltre, è (generalmente) un'idea migliore per attraversare l'elenco per * rimuovere *, poiché è solitamente più piccolo. Stai anche costringendo più traversali di liste a farlo in questo modo. –

10

Si potrebbe usare LINQ, ma vorrei andare con RemoveAll metodo. Penso che sia quello che esprime meglio le tue intenzioni.

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 ancora più semplice con i gruppi di metodi che puoi fare - interi.RimuoviTutti (remove.Contains); – Ryan

4

Soluzione 1: Si può fare in questo modo:

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

Ma in alcuni casi può questa soluzione non funziona. se non funziona, puoi usare la mia seconda soluzione.

Soluzione 2:

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

abbiamo finta che lista1 è la vostra lista principale e lista2 è la vostra lista secondry e si desidera ottenere elementi di lista1 senza elementi di lista2.

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

Nel mio caso ho avuto due elenchi diversi, con un identificatore comune, un po 'come una chiave esterna. La seconda soluzione citata da "nzrytmn":

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

Era quello che meglio si adatta nella mia situazione. Avevo bisogno di caricare un DropDownList senza i record che erano già stati registrati.

Grazie !!!

Questo è il mio codice:

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" :-) –

Problemi correlati