2013-10-04 4 views
16

Mam 2 listy różnych obiektów (foo & bar), które dzielą tę samą nieruchomość, można ją nazwać id.Usuwanie elementów z listy, które krzyżują się z nieruchomościami przy użyciu Linq

public List<foo> foo { get; set; } 
public List<bar> bar { get; set; } 

Chcę usunąć wszystkie obiekty z foo które posiadają identyfikator, który nie istnieje w bar

Jak można to zrobić w LINQ? Patrzę na Intersect, RemoveAll & Join, ale nie mogę znaleźć żadnego przykładu, w którym listy są innego typu.

Odpowiedz

23

Spróbuj tego:

foo.RemoveAll(x=> !bar.Any(y=>y.Id==x.Id)); 

!bar.Any(y=>y.Id==x.Id) dostanie, jeśli element jest w bar kolekcji, a jeśli to nie usunie go z foo kolekcji.

Lepsze rozwiązanie wykorzystujące HashSet O (n):

var idsNotToBeRemoved = new HashSet<int>(bar.Select(item => item.Id));                      
foo.RemoveAll(item => !idsNotToBeRemoved.Contains(item.Id)); 

źródło drugiego odpowiedzi: https://stackoverflow.com/a/4037674/1714342

Edycja:

jak @Carra że pierwsze rozwiązanie jest dobre w przypadku małych list i drugim jest bardziej wydajny w przypadku dużych list.

+1

Brilliant @wudzik – ojhawkins

+2

Dla małych list, pierwszy zrobi. Jeśli używasz dużych list (> 100 lub więcej), lepiej jest użyć drugiego rozwiązania. – Carra

7
var foo = foo.Where(f => !bar.Any(b => b.Id == f.Id)).ToList(); 

Pamiętaj, że jest to rozwiązanie O (n²), nie będzie działać dobrze na dużych listach.

+0

Jakie byłoby bardziej skuteczne rozwiązanie tego problemu? @Carra – ojhawkins

+0

@ojhawkins Jednym z rozwiązań byłoby wstępne pobranie listy 'id's z' bar' do hashset (O (n)), a następnie porównanie każdego elementu w 'foo' do tego (O (n)) niż chodzenie po liście 'bar' dla każdego elementu w' foo' –

+0

tak Widziałem przykład Jona Skeetsa tutaj, ale nie mogłem go zastosować do mojego przykładu http://stackoverflow.com/questions/853526/using-linq-to-remove -objects-in-a-listt – ojhawkins

Powiązane problemy