So reduzieren Sie verschachtelte Objekte mit dem Linq-Ausdruck


125

Ich versuche, verschachtelte Objekte wie folgt zu reduzieren:

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

Lassen Sie mich ein Beispiel geben. Dies sind die Daten, die ich habe

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

Das Ergebnis, das ich suche, ist die folgende flache Liste:

"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"

Wie könnte ich das erreichen? Ich könnte es mit einem Select New machen, aber mir wurde gesagt, dass ein SelectMany ausreichen würde.

Antworten:


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

Genial!!! Was wäre, wenn ich ein neues Objekt wie FlatBook {BookName, ChapterName, PageName} erhalten würde?
abx78

2
@ abx78: ändern Sie einfach die letzte Auswahl:.Select(p => new FlatBook(b.Name, c.Name, p.Name))
user7116

Danke Jungs, das war was ich brauche!
abx78

1
führt dies zum gleichen Ergebnis? myBooks.SelectMany(b => b.Chapters).SelectMany(c => c.Pages).Select(p => b.Name + ", " + c.Name + ", " + p.Name);
Homer

1
@ Mastro wie wäre esmyBooks.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

Angenommen, es booksist eine Liste von Büchern:

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, obwohl jeder IEnumerable<Book>es tun wird, braucht kein 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
Dieses Codebeispiel beantwortet möglicherweise die Frage, es fehlt jedoch eine Erklärung. So wie es jetzt ist, fügt es keinen Wert hinzu und steht für die Änderung der Herabstufung / Löschung. Bitte fügen Sie eine Erklärung hinzu, was funktioniert und warum es eine Lösung für das Problem des OP ist.
2.

0

Ich habe versucht, dies auch zu tun, und aus Yuriys Kommentaren und dem Durcheinander mit linqPad habe ich dies ..

Beachten Sie, dass ich keine Bücher, Kapitel, Seiten, Personen (Bücher), Unternehmenspersonen (Kapitel) und Unternehmen (Seiten) habe.

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

oder

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

Von mir verwendete Referenzseite : http://odetocode.com/blogs/scott/archive/2008/03/25/inner-outer-lets-all-join-together-with-linq.aspx

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.