Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SelectMany Three Levels Deep

Tags:

I can flatten the results of a child collection within a collection with SelectMany:

 // a list of Foos, a Foo contains a List of Bars  var source = new List<Foo>() { ... };   var q = source.SelectMany(foo => foo.Bar)      .Select(bar => bar.barId)  .ToList(); 

this gives me the list of all Bar Ids in the Foo List. When I attempt to go three levels deep the incorrect result is returned.

 var q = source.SelectMany(foo => foo.Bar)      .SelectMany(bar => bar.Widget)          .Select(widget => widget.WidgetId)  .ToList(); 

How should I be using SelectMany to get the list of all Widgets in all Bars in my list of Foos?

Edit I miss-worded the above sentence, but the code reflects the goal. I am looking for a list of all Widget Ids, not widgets.

An "incorrect" result is not all of the widget ids are returned.

like image 937
blu Avatar asked Mar 12 '09 20:03

blu


2 Answers

Your query is returning all the widget IDs, instead of all the widgets. If you just want widgets, just use:

var q = source.SelectMany(foo => foo.Bar)               .SelectMany(bar => bar.Widget)               .ToList(); 

If that's still giving "the incorrect result" please explain in what way it's the incorrect result. Sample code would be very helpful :)

EDIT: Okay, if you want the widget IDs, your original code should be fine:

var q = source.SelectMany(foo => foo.Bar)               .SelectMany(bar => bar.Widget)               .Select(widget => widget.WidgetId)               .ToList(); 

That could also be written as

var q = (from foo in source          from bar in foo.Bar          from widget in bar.Widget          select widgetId).ToList(); 

if you like query expression format.

This really should work - if it's not working, that suggests there's something wrong with your data.

We should have checked before - is this just LINQ to Objects, or a fancier provider (e.g. LINQ to SQL)?

like image 199
Jon Skeet Avatar answered Oct 14 '22 06:10

Jon Skeet


var q = (     from f in foo     from b in f.Bars     from w in b.Widgets     select w.WidgetId    ).ToList(); 

Also note that if you want the unique list, you can do .Distinct().ToList() instead.

like image 43
eglasius Avatar answered Oct 14 '22 08:10

eglasius