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.

abx78
quelle

Antworten:

199
myBooks.SelectMany(b => b.Chapters
    .SelectMany(c => c.Pages
        .Select(p => b.Name + ", " + c.Name + ", " + p.Name)));
Yuriy Faktorovich
quelle
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};
Boca
quelle
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
                });
Madhukar Bhandari
quelle
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

Mastro
quelle