Cách làm phẳng các đối tượng lồng nhau bằng biểu thức linq


125

Tôi đang cố gắng làm phẳng các đối tượng lồng nhau như thế này:

public class Book
{
    public string Name { get; set; }
    public IList<Chapter> Chapters { get; set; }
}

public class Chapter
{
    public string Name { get; set; }
    public IList<Page> Pages { get; set; }
}


public class Page
{
    public string Name { get; set; }
}

Hãy để tôi làm một ví dụ. Đây là dữ liệu tôi có

Book: Pro Linq 
{ 
   Chapter 1: Hello Linq 
   {
      Page 1, 
      Page 2, 
      Page 3
   },
   Chapter 2: C# Language enhancements
   {
      Page 4
   },
}

Kết quả tôi đang tìm là danh sách phẳng sau:

"Pro Linq", "Hello Linq", "Page 1"
"Pro Linq", "Hello Linq", "Page 2"
"Pro Linq", "Hello Linq", "Page 3"
"Pro Linq", "C# Language enhancements", "Page 4"

Làm thế nào tôi có thể thực hiện điều này? Tôi có thể làm điều đó với một lựa chọn mới nhưng tôi đã được thông báo rằng một SelectMany là đủ.

Câu trả lời:


199
myBooks.SelectMany(b => b.Chapters
    .SelectMany(c => c.Pages
        .Select(p => b.Name + ", " + c.Name + ", " + p.Name)));

Tuyệt vời!!! Điều gì xảy ra nếu tôi nhận được kết quả là một đối tượng mới, như FlatBook {BookName, ChapterName, PageName}?
abx78

2
@ abx78: chỉ đơn giản là thay đổi người cuối cùng chọn:.Select(p => new FlatBook(b.Name, c.Name, p.Name))
user7116

Cảm ơn các bạn, đây là những gì tôi cần!
abx78

1
Điều này có tạo ra cùng một kết quả không? myBooks.SelectMany(b => b.Chapters).SelectMany(c => c.Pages).Select(p => b.Name + ", " + c.Name + ", " + p.Name);
Homer

1
@Mastro thế nào vềmyBooks.SelectMany(b => b.Chapters == null || !b.Chapters.Any()? new []{b.Name + " has no Chapters"} : b.SelectMany(c => c.Pages.Select(p => b.Name + ", " + c.Name + ", " + p.Name)));
Yuriy Faktorovich

50

Giả sử bookslà một Danh sách Sách:

var r = from b in books
    from c in b.Chapters
    from p in c.Pages
    select new {BookName = b.Name, ChapterName = c.Name, PageName = p.Name};

2
+1, mặc dù bất kỳ IEnumerable<Book>ý muốn nào, không cần a List<Book>.
user7116

2
myBooks.SelectMany(b => b.Chapters
    .SelectMany(c => c.Pages
        .Select(p => new 
                {
                    BookName = b.Name ,
                    ChapterName = c.Name , 
                    PageName = p.Name
                });

7
Mặc dù mẫu mã này có thể trả lời câu hỏi, nhưng nó thiếu giải thích. Như hiện tại, nó không có thêm giá trị nào và đứng trước sự thay đổi của việc bị phản đối / xóa bỏ. Vui lòng thêm một số lời giải thích là gì và tại sao nó là một giải pháp cho vấn đề của OP.
oɔɯǝɹ

0

Tôi cũng đang cố gắng làm điều này, và từ những bình luận của Yuriy và sự cố với linqPad, tôi có cái này ..

Lưu ý rằng tôi không có sách, chương, trang, tôi có người (sách), công ty (chương) và công ty (trang)

from person in Person
                           join companyPerson in CompanyPerson on person.Id equals companyPerson.PersonId into companyPersonGroups
                           from companyPerson in companyPersonGroups.DefaultIfEmpty()
                           select new
                           {
                               ContactPerson = person,
                               ContactCompany = companyPerson.Company
                           };

hoặc là

Person
   .GroupJoin (
      CompanyPerson, 
      person => person.Id, 
      companyPerson => companyPerson.PersonId, 
      (person, companyPersonGroups) => 
         new  
         {
            person = person, 
            companyPersonGroups = companyPersonGroups
         }
   )
   .SelectMany (
      temp0 => temp0.companyPersonGroups.DefaultIfEmpty (), 
      (temp0, companyPerson) => 
         new  
         {
            ContactPerson = temp0.person, 
            ContactCompany = companyPerson.Company
         }
   )

Tham khảo trang web tôi đã sử dụng: http://odetocode.com/blogs/scott/archive/2008/03/25/inner-outer-lets-all-join-together-with-linq.aspx

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.