2010-04-30 17 views
126

Próbuję dowiedzieć się, jak przejść ogólną listę elementów, które chcę usunąć z innej listy elementów.Usuwanie elementów z jednej listy w innej

Więc powiedzmy, że mam to jako hipotetyczny przykład

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

chcę przechodzić list1 z foreach i usunąć każdą pozycję listy1 który jest również zawarty w lista2.

Nie jestem do końca pewien, jak to zrobić, ponieważ foreach nie jest oparty na indeksach.

+1

chcesz usunąć elementy listy1 które są również w lista2? –

+0

Musisz usunąć elementy z listy1 i dodać je do listy2 lub innej? – danish

+0

Powiązane: http://stackoverflow.com/questions/2477633/a-question- about-comparing-listt –

Odpowiedz

246

Można użyć Except:

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

Prawdopodobnie nie trzeba nawet te zmienne tymczasowe:

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

Zauważ, że Except nie zmienia żadnej z list - tworzy nowy lista z wynikiem.

+8

Niewielki punkt, ale spowoduje powstanie 'IEnumerable ', a nie 'List '. Musisz wywołać 'ToList()', aby odzyskać listę. Ponadto uważam, że powinno to być 'GetSomeOtherList() .Z wyjątkiem (GetTheList()) .ToList()' –

+5

Będziesz także potrzebował 'using System.Linq;' jeśli nie miałeś go wcześniej. – yellavon

+0

Dodałem przy użyciu System.Linq, ale nadal nie mogę uzyskać dostępu z wyjątkiem. Ale w moim przypadku używam ArrayList. Jakieś pomysły na to, jak sprawić, by działał z ArrayList? – BKSpurgeon

23

Nie potrzebujesz indeksu, ponieważ klasa List<T> pozwala na usuwanie pozycji według wartości zamiast indeksu przy użyciu funkcji Remove.

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

+1, ale IMO należy używać nawiasów wokół instrukcji 'list2.Remove (item);'. – ANeves

+2

@sr pt: Zawsze używam nawiasów na instrukcjach, które pojawiają się w innym wierszu, ale nie na blokach pojedynczej instrukcji, które mogę umieścić w tym samym wierszu, co instrukcja sterowania przepływem. –

+0

Dopóki jesteś konsekwentny, nie ma znaczenia, czy używasz nawiasów, czy nie .. IMO :) –

21

Polecam korzystanie z LINQ extension methods. Można łatwo zrobić to z jednej linii kodu tak:

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

to zakładając oczywiście obiekty w listy1 że usuwasz z listy2 są takie same instancji.

+1

Usuwa również duplikaty. –

-4

Tu 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. Spowoduje to zgłoszenie wyjątku po usunięciu pierwszego elementu. Lepiej jest też przejść przez * listę * do * usunięcia *, ponieważ jest zwykle mniejsza. Zmuszasz też do tego, aby więcej wykonawców list wykonało w ten sposób. –

10

Można użyć LINQ, ale pójdę z RemoveAll metody. Myślę, że to jest ten, który lepiej wyraża twój zamiar.

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

Lub jeszcze prostsze z grup metod można zrobić - integers.RemoveAll (remove.Contains); – Ryan

4

Rozwiązanie 1: Można zrobić tak:

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

Jednak w niektórych przypadkach może to rozwiązanie nie działa. jeśli to nie działa, możesz użyć mojego drugiego rozwiązania.

Rozwiązanie 2:

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

udajemy, że list1 jest głównej liście i lista2 to secondry lista i chcesz dostać pozycje listy1 bez elementów listy2.

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

W moim przypadku miałem dwie różne listy, ze wspólnym identyfikatorem, coś w rodzaju klucza obcego. Drugie rozwiązanie cytowany przez „nzrytmn”:

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

Czy ten, który najlepiej pasuje do mojej sytuacji. Potrzebowałem załadować DropDownList bez zapisów, które zostały już zarejestrowane.

Dziękujemy!

To jest mój kod:

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