Comment aplatir des objets imbriqués avec une expression linq


125

J'essaye d'aplatir les objets imbriqués comme ceci:

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

Laissez-moi faire un exemple. Ce sont les données que j'ai

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

Le résultat que je recherche est la liste plate suivante:

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

Comment pourrais-je accomplir cela? Je pourrais le faire avec un nouveau select mais on m'a dit qu'un SelectMany suffirait.

Réponses:


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

Impressionnant!!! Et si j'aurais comme résultat un nouvel objet, comme FlatBook {BookName, ChapterName, PageName}?
abx78 le

2
@ abx78: modifiez simplement la dernière sélection:.Select(p => new FlatBook(b.Name, c.Name, p.Name))
user7116

Merci les gars, c'est ce dont j'ai besoin!
abx78

1
cela produit-il le même résultat? myBooks.SelectMany(b => b.Chapters).SelectMany(c => c.Pages).Select(p => b.Name + ", " + c.Name + ", " + p.Name);
Homer

1
@Mastro how aboutmyBooks.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

En supposant booksune liste de livres:

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ême si n'importe lequel IEnumerable<Book>fera l'affaire, n'a pas besoin d'un 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
Bien que cet exemple de code puisse répondre à la question, il manque d'explication. Dans l'état actuel des choses, il n'ajoute aucune valeur et résiste au changement de vote défavorable / supprimé. Veuillez ajouter quelques explications sur ce que fait et pourquoi c'est une solution au problème du PO.
oɔɯǝɹ

0

J'essayais de le faire aussi, et d'après les commentaires de Yuriy et le fait de jouer avec linqPad, j'ai ceci ...

Notez que je n'ai pas de livres, chapitres, pages, j'ai personne (livres), entreprisePersonne (chapitres) et entreprises (pages)

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

ou

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

Site de référence que j'ai utilisé: http://odetocode.com/blogs/scott/archive/2008/03/25/inner-outer-lets-all-join-together-with-linq.aspx

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.