2011-08-04 19 views
12

szukam eleganckie rozwiązanie dla następującej sytuacji:Unia wielokrotnością list w C#

Mam klasa, która zawiera listę jak

class MyClass{ 
... 
public List<SomeOtherClass> SomeOtherClassList {get; set;} 
... 
} 

Trzecia klasa nazywa Model trzyma List<Myclass> z którego operuję z zewnątrz.

Teraz chciałbym rozszerzyć klasę Model za pomocą metody zwracającej wszystkie unikalne instancje SomeOtherClass we wszystkich instancjach MyClass.

Wiem, że istnieje metoda Union() i za pomocą pętli foreach mogę rozwiązać ten problem z łatwością, co faktycznie zrobiłem. Jednakże, ponieważ jestem nowy we wszystkich funkcjach C# 3 +, jestem ciekawy, jak można to osiągnąć bardziej elegancko, z lub bez Linq.

znalazłem podejście, które wydaje się raczej niezgrabny do mnie, ale to działa:

 List<SomeOtherClass> ret = new List<SomeOtherClass>(); 
     MyClassList.Select(b => b.SomeOtherClasses).ToList().ForEach(l => ret = ret.Union(l).ToList()); 
     return ret; 

Uwaga: Właściwość b.SomeotherClasses zwraca List<SomeOtherClasses>.

Kod ten jest daleki od doskonałości, a niektóre pytania wynikają z faktu, że muszę wymyślić, co jest dobrym stylem do pracy z C# 3, a co nie. Zrobiłem więc małą listę z przemyśleniami na temat tego fragmentu, z którego chętnie przeczytam kilka komentarzy. Poza tym chętnie usłyszę kilka komentarzy, jak ulepszyć ten kod.

  • Lista tymczasowa ret byłby częścią podejścia w C# 2 Być może, ale czy to prawda, że ​​powinienem być w stanie zrezygnować z tej listy za pomocą metody łańcuchowy zamiast? Czy może brakuje mi punktu?
  • Czy naprawdę wymagane jest stosowanie metody pośredniej ToList()? Wszystko, czego chcę, to wykonać kolejną akcję dla każdego członka selekcji.
  • Jaki jest koszt tych operacji ToList()? Czy są w dobrym stylu? Niezbędny?

Dzięki.

+0

Co znaczy tu wyjątkowy? Mam na myśli, czy przechowujesz wiele odniesień do tego samego obiektu na liście 'List '? –

Odpowiedz

25

Szukasz SelectMany() + Distinct():

List<SomeOtherClass> ret = MyClassList.SelectMany(x => x.SomeOtherClasses) 
             .Distinct() 
             .ToList(); 

SelectMany() będzie spłaszczyć „listę list” do jednej listy, to możesz po prostu wybrać się na różne pozycje w tym wyliczenia zamiast używać unię między poszczególnymi pod-listy.

Generalnie powinieneś unikać efektów ubocznych za pomocą Linq, twoje oryginalne podejście jest w pewnym sensie nadużywające mojej modyfikacji ret, która nie jest częścią zapytania.

ToList() jest wymagany, ponieważ każdy standardowy operator zapytań zwraca nowe wyliczenie i nie modyfikuje istniejącego wyliczenia, dlatego należy przekonwertować końcowy wynik wyliczenia z powrotem na listę. Koszt ToList() jest pełną iteracją wyliczenia, które w większości przypadków jest pomijalne. Oczywiście, jeśli twoja klasa może zamiast tego używać IEnumerable<SomeOtherClass>, nie musisz w ogóle konwertować na listę.

+0

Idealne, właśnie tego szukałem. To rozwiąże problem, a także usunie pośredni krok .ToList(). Dzięki, nauczyłem się czegoś dzisiaj. Piątek jest dobry. :-) –

0

Powinieneś rzucić okiem na SelectMany.Coś takiego powinno wygenerować „płaską” listy:

MyClassList.SelectMany(b => b.SomeOtherClasses) 

To zwróci IEnumerable<SomeOtherClass> który można filtrować/proces dalej.