SelectMany Three Levels Deep

2019-03-12 09:41发布

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.

3条回答
【Aperson】
2楼-- · 2019-03-12 10:19
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.

查看更多
ら.Afraid
3楼-- · 2019-03-12 10:33

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

查看更多
仙女界的扛把子
4楼-- · 2019-03-12 10:33
       var q = source.SelectMany(foo => foo.Bar)
          .SelectMany(bar => bar.Widget,(bar,widget) => widget.WidgetId)
          .ToList();

we can call this overload of SelectMany() with allow us to specify the projection using lambda experession

查看更多
登录 后发表回答