Подтвердить что ты не робот

LINQ: Как получить элементы из внутреннего списка в один список?

Имея следующие классы (очень упрощенные):

public class Child
{
    public string Label;
    public int CategoryNumber;
    public int StorageId;
}

public class Parent
{
    public string Label;
    public List<Child> Children = new List<Child>();
}

И имея следующие данные:

var parents = new List<Parent>();

var parent = new Parent() {Label="P1"};
parent.Children.Add(new Child() {Label="C1", CategoryNumber=1, StorageId=10});
parent.Children.Add(new Child() {Label="C2", CategoryNumber=2, StorageId=20});
parents.Add(parent);

parent = new Parent() {Label="P2"};
parent.Children.Add(new Child() {Label="C3", CategoryNumber=1, StorageId=10});
parent.Children.Add(new Child() {Label="C4", CategoryNumber=2, StorageId=30});
parents.Add(parent);

parent = new Parent() {Label="P3"};
parent.Children.Add(new Child() {Label="C5", CategoryNumber=3, StorageId=10});
parent.Children.Add(new Child() {Label="C6", CategoryNumber=2, StorageId=40});
parents.Add(parent);

Теперь, как бы получить список детей (с CategoryNumber = 2) из ​​списка родителей, содержащих хотя бы одного ребенка с CategoryNumber = 1?

Я могу сделать следующее, но оно не кажется оптимальным:

var validParents = from p in parents
                   where p.Children.Any (c => c.CategoryNumber==1)
                   select p;
var selectedChildren = validParents.Select(p => from c in p.Children 
                                                where c.CategoryNumber == 2
                                                select c);

Здесь я получаю для selectedChildren:

  • IEnumerable<IEnumerable<Child>>
    • IEnumerable<Child>
      • C2 2 20
    • IEnumerable<Child>
      • C4 2 30

Возможно ли иметь только один плоский список, содержащий два дочерних элемента вместо двух подписок? Как это перевести в LINQ?

4b9b3361

Ответ 1

Скотт ответ велик; Я просто хотел бы указать, что вы действительно можете сделать этот запрос, используя синтаксис продолжения запроса:

from parent in parents 
where parent.Children.Any (c => c.CategoryNumber==1)
select parent into p
from child in p.Children
where child.CategoryNumber == 2
select child

Обратите внимание, что "в" позволяет передать результат одного запроса в следующий запрос. Довольно скользкий, а??

Ответ 2

Вы можете связать пару запросов вместе, используя SelectMany и Где.

var selectedChildren = (from p in parents
                       where p.Children.Any (c => c.CategoryNumber==1)
                       select p)
                       .SelectMany(p => p.Children)
                       .Where(c => c.CategoryNumber == 2);

// or...

var selectedChildren = parents
                         .Where(p => p.Children.Any(c => c.CategoryNumber == 1))
                         .SelectMany(p => p.Children)
                         .Where(c => c.CategoryNumber == 2);