How to flatten nested objects with linq expression
75,717
Solution 1
myBooks.SelectMany(b => b.Chapters
.SelectMany(c => c.Pages
.Select(p => b.Name + ", " + c.Name + ", " + p.Name)));
Solution 2
Assuming books
is a List of Book:
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};
Solution 3
myBooks.SelectMany(b => b.Chapters
.SelectMany(c => c.Pages
.Select(p => new
{
BookName = b.Name ,
ChapterName = c.Name ,
PageName = p.Name
});
Author by
ab_732
Updated on July 08, 2022Comments
-
ab_732 almost 2 years
I am trying to flatten nested objects like this:
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; } }
Let me make an example. This is the data I have
Book: Pro Linq { Chapter 1: Hello Linq { Page 1, Page 2, Page 3 }, Chapter 2: C# Language enhancements { Page 4 }, }
The result I am looking for is the following flat list:
"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"
How could I accomplish this? I could do it with a select new but I've been told that a SelectMany would be enough.
-
Sam almost 13 years+1, even though any
IEnumerable<Book>
will do, doesn't need aList<Book>
. -
ab_732 almost 13 yearsAwesome!!! What if I would have a result a new object, like FlatBook{BookName, ChapterName, PageName} ?
-
Sam almost 13 years@abx78: simply alter the last select:
.Select(p => new FlatBook(b.Name, c.Name, p.Name))
-
ab_732 almost 13 yearsThank you guys, this was what I need!
-
Homer about 11 yearsdoes this produce the same result?
myBooks.SelectMany(b => b.Chapters).SelectMany(c => c.Pages).Select(p => b.Name + ", " + c.Name + ", " + p.Name);
-
The Muffin Man almost 11 yearsSo how would you rewrite this to support an N number of nested objects?
-
Mastro almost 10 yearsIs there a way to do this but include any Books that do not have Chapters?
-
Yuriy Faktorovich almost 10 years@Mastro start it with
myBooks.Where(b => b.Chapters != null)
-
Mastro almost 10 yearsHmm well I wanted a list where both are shown. what you have here is where not null, I wanted a flatten list where I also, include the nulls but doesn't seem to work if I do Where(b => b.Chapters == null) as I get 0. Would like to have a flatten list with all books, ones with or without chapters. Is that possible? Or do I need some type of union?
-
Yuriy Faktorovich almost 10 years@Mastro how about
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)));
-
Mastro almost 10 yearsOk that code didn't help but it got my on my track to solving it. So gonna vote up your comment for the effort.
-
Yuriy Faktorovich almost 10 years@Mastro did I misunderstand what you were asking? What was the solution?
-
Mastro almost 10 yearsWell I couldn't get yours to compile but I don't have books to chapters, I have projects(b) to companyperson(c) to companies(p). So I used linqPad and created a left join query. Too long to post here it seems, I'll post as an answer.
-
oɔɯǝɹ over 9 yearsWhile this code sample may answer the question, it lacks explanation. As it stands now, it adds no value, and stands the change of being downvoted / deleted. Please add some explanation what is does and why it is a solution for the problem of the OP.
-
Dejavu about 7 years@Homer: I don't think your solution is possible, since
b
andc
are inaccessible from the lastSelect
clause. See live demo: rextester.com/BHNH3184 -
Homer about 7 years@Dejavu, yeah my comment stinks. I'm not even sure what the point of it was.
-
mko about 6 years@YuriyFaktorovich but book.name is missing. this code only joins data from chapters and its childs
-
Pouya BCD over 5 yearsSuccinct! Thanks.