2009-06-22 32 views
28

Có các lớp sau (cao đơn giản):LINQ: Làm cách nào để lấy các mục từ danh sách bên trong vào một danh sách?

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>(); 
} 

Và có các dữ liệu sau:

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); 

Bây giờ, làm thế nào tôi sẽ nhận được một danh sách các trẻ em (với CategoryNumber = 2) từ danh sách của cha mẹ có chứa ít nhất một đứa trẻ với CategoryNumber = 1?

tôi có thể làm như sau nhưng nó không xuất hiện để được tối ưu:

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); 

Đây là những gì tôi nhận được cho selectedChildren:

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

Có thể chỉ có một danh sách phẳng chứa các yếu tố hai đứa con thay vì hai tiểu danh sách? Làm thế nào nó sẽ dịch trong LINQ?

Trả lời

33

Scott Câu trả lời là tuyệt vời; Tôi chỉ muốn chỉ ra rằng bạn có thể trong thực tế làm truy vấn này sử dụng truy vấn tiếp cú pháp:

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 

Chú ý cách các "thành" cho phép bạn ống kết quả của một truy vấn vào truy vấn tiếp theo . Khá trơn nhỉ?

+1

@Eric: Vâng, cú pháp truy vấn LINQ cho điều này là khá tốt đẹp (và có lẽ tốt hơn một chút để sử dụng như trái ngược với cú pháp truy vấn trộn và phương pháp mở rộng). Bất cứ khi nào tôi gặp chủ đề này, tôi cảm thấy LINQ thiếu một toán tử nối (tương tự như Seq.concat trong F #), có thể được sử dụng như một giải pháp thay thế cho SelectMany, và thực sự rất tiện dụng trong các trường hợp khác. Một quá tải đơn giản của phương thức Enumerable.Concat có tham số IEnumerable > sẽ thực hiện công việc khá tốt. Bất kỳ suy nghĩ (hoặc thậm chí tốt hơn, kế hoạch) liên quan đến điều này? – Noldorin

+0

Ah, có vẻ như MoreLINQ định nghĩa toán tử này: http://code.google.com/p/morelinq/wiki/OperatorsOverview. Nó sẽ là khá tốt đẹp để có trong BCL mặc dù (cùng với một vài người khác như Zip). – Noldorin

+0

cảm ơn ... bạn đã cứu ngày của tôi – thiagolsilva

41

Bạn có thể ghép nối một vài truy vấn với nhau, sử dụng SelectManyWhere.

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

Hoạt động tuyệt vời! SelectMany có vẻ là một phương pháp hữu ích. Bạn có bất cứ đề nghị nào cho một trang web hoặc một cuốn sách về sự hiểu biết đầy đủ về LINQ? –

+0

Đối với các trang web, trang bạn đang truy cập là tốt - hầu hết các vấn đề về LINQ của tôi đã được giải quyết bằng một câu hỏi tìm kiếm hoặc đăng nhanh tại đây. cuốn sách duy nhất mà tôi đã xem là cuốn sách này ... 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

Cảm ơn bạn đã cung cấp thêm một cú pháp! – Peter

Các vấn đề liên quan