2009-06-22 24 views
28

uwzględniając następujące klasy (bardzo uproszczony):LINQ: Jak pobrać elementy z wewnętrznej listy do jednej listy?

public class Child 
{ 
    public string Label; 
    public int CategoryNumber; 
    public int StorageId; 
} 

public class Parent 
{ 
    public string Label; 
    public List<Child> Children = new List<Child>(); 
} 

i posiadające następujące dane:

var parents = new List<Parent>(); 

var parent = new Parent() {Label="P1"}; 
parent.Children.Add(new Child() {Label="C1", CategoryNumber=1, StorageId=10}); 
parent.Children.Add(new Child() {Label="C2", CategoryNumber=2, StorageId=20}); 
parents.Add(parent); 

parent = new Parent() {Label="P2"}; 
parent.Children.Add(new Child() {Label="C3", CategoryNumber=1, StorageId=10}); 
parent.Children.Add(new Child() {Label="C4", CategoryNumber=2, StorageId=30}); 
parents.Add(parent); 

parent = new Parent() {Label="P3"}; 
parent.Children.Add(new Child() {Label="C5", CategoryNumber=3, StorageId=10}); 
parent.Children.Add(new Child() {Label="C6", CategoryNumber=2, StorageId=40}); 
parents.Add(parent); 

Teraz, w jaki sposób uzyskać listę dzieci (z CategoryNumber = 2) z listy rodziców zawierających co najmniej jedno dziecko z CategoryNumber = 1?

mogę wykonać następujące czynności, ale nie wydaje się być optymalny:

var validParents = from p in parents 
        where p.Children.Any (c => c.CategoryNumber==1) 
        select p; 
var selectedChildren = validParents.Select(p => from c in p.Children 
               where c.CategoryNumber == 2 
               select c); 

Oto co mam do selectedChildren:

  • IEnumerable<IEnumerable<Child>>
    • IEnumerable<Child>
      • C2 2 20
    • IEnumerable<Child>
      • C4 2 30

Czy możliwe jest tylko jedną listę zawierającą płaską dwojga dzieci elementy zamiast dwóch sub-liście? Jak by to tłumaczyło w LINQ?

Odpowiedz

33

Scott Odpowiedź jest świetna; Chciałbym tylko zwrócić uwagę, że można rzeczywiście zrobić to zapytanie korzystając kontynuacji kwerendy składni:

from parent in parents 
where parent.Children.Any (c => c.CategoryNumber==1) 
select parent into p 
from child in p.Children 
where child.CategoryNumber == 2 
select child 

Wskazówki jak W „do” pozwala rurę wynikiem jednego zapytania do następnego zapytania . Dość śliski, co?

+1

@Eric: Tak, składnia zapytań LINQ jest całkiem niezła (i prawdopodobnie nieco lepsza w użyciu w przeciwieństwie do mieszania składni zapytania i metody rozszerzenia). Ilekroć napotykam ten temat, mam jednak wrażenie, że LINQ brakuje operatora konkatenacji (podobnego do Seq.concat w F #), który może być używany jako alternatywa dla SelectMany i jest rzeczywiście bardzo przydatny w innych przypadkach. Proste przeciążenie metody Enumerable.Concat, która pobiera parametr IEnumerable >, wykonałoby to całkiem dobrze. Wszelkie przemyślenia (lub nawet lepsze, plany) dotyczące tego? – Noldorin

+0

Ah, wygląda na to, że MoreLINQ definiuje ten operator: http://code.google.com/p/morelinq/wiki/OperatorsOverview. Byłoby całkiem fajnie mieć w BCL (wraz z kilkoma innymi, takimi jak Zip). – Noldorin

+0

dzięki ... uratujesz mi dzień – thiagolsilva

41

Możesz połączyć kilka zapytań ze sobą, używając SelectMany i Where.

var selectedChildren = (from p in parents 
         where p.Children.Any (c => c.CategoryNumber==1) 
         select p) 
         .SelectMany(p => p.Children) 
         .Where(c => c.CategoryNumber == 2); 

// or... 

var selectedChildren = parents 
         .Where(p => p.Children.Any(c => c.CategoryNumber == 1)) 
         .SelectMany(p => p.Children) 
         .Where(c => c.CategoryNumber == 2); 
+0

Działa doskonale! SelectMany wydaje się być użyteczną metodą. Czy masz jakieś sugestie dotyczące strony internetowej lub książki o pełnym zrozumieniu Linq? –

+0

W przypadku witryn ten, w którym się znajdujesz jest dobry - większość moich problemów z linq zostało rozwiązanych dzięki szybkiemu wyszukiwaniu lub opublikowaniu pytania tutaj. jedyną książką, na którą patrzę, jest ta ... http://www.amazon.com/Programming-Microsoft%C2%AE-PRO-Developer-Paolo-Pialorsi/dp/0735624003/ref=sr_1_23?ie = UTF8 & s = books & qid = 1245694305 & sr = 8-23 –

+0

Dzięki za dostarczenie więcej niż jednej składni! – Peter

Powiązane problemy