SelectMany Three Levels Deep
Я могу сгладить результаты дочерней коллекции в коллекции с помощью 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();
это дает мне список всех идентификаторов Bar в списке Foo. Когда я пытаюсь пройти три уровня, возвращается неправильный результат.
var q = source.SelectMany(foo => foo.Bar)
.SelectMany(bar => bar.Widget)
.Select(widget => widget.WidgetId)
.ToList();
Как я должен использовать SelectMany, чтобы получить список всех виджетов на всех барах в моем списке Foos?
Edit
Я пропустил вышеупомянутое предложение, но код отражает цель. Я ищу список всех идентификаторов виджетов, а не виджеты.
"Неверный" результат - это не все идентификаторы виджетов.
Ответы
Ответ 1
Ваш запрос возвращает все идентификаторы виджетов, а не все виджеты. Если вам просто нужны виджеты, просто используйте:
var q = source.SelectMany(foo => foo.Bar)
.SelectMany(bar => bar.Widget)
.ToList();
Если это все еще дает "неправильный результат", пожалуйста, объясните, каким образом это неправильный результат. Пример кода будет очень полезен:)
EDIT: Хорошо, если вам нужны идентификаторы виджетов, ваш исходный код должен быть в порядке:
var q = source.SelectMany(foo => foo.Bar)
.SelectMany(bar => bar.Widget)
.Select(widget => widget.WidgetId)
.ToList();
Это также можно записать как
var q = (from foo in source
from bar in foo.Bar
from widget in bar.Widget
select widgetId).ToList();
если вам нравится формат выражения запроса.
Это действительно должно сработать - если оно не работает, это говорит о том, что что-то не так с вашими данными.
Мы должны были проверить раньше - это просто LINQ to Objects или поставщик фанов (например, LINQ to SQL)?
Ответ 2
var q = (
from f in foo
from b in f.Bars
from w in b.Widgets
select w.WidgetId
).ToList();
Также обратите внимание, что если вам нужен уникальный список, вы можете сделать .Distinct(). ToList().
Ответ 3
var q = source.SelectMany(foo => foo.Bar)
.SelectMany(bar => bar.Widget,(bar,widget) => widget.WidgetId)
.ToList();
мы можем вызвать эту перегрузку SelectMany(), чтобы мы могли указать проекцию, используя лямбда-эксперимент