2016-03-04 4 views
2

У меня есть список магазинов (типа ObservableCollection<Store>) и Store объект имеет свойство Особенности (типа List<Feature>). и объект Feature имеет Наименование (тип string).LINQ Intersect на внутренней коллекции

Напомним, список магазинов, который имеет список всех функций

У меня есть вторая коллекция DesiredFeatures (типа List<string>).

мне нужно использовать LINQ, чтобы дать мне результаты из только магазины, которые имеют все в DesiredFeatures. До сих пор я только мог придумать запрос, который дает мне ИЛИ результат вместо И.

Вот как это выглядит:

var q = Stores.Where(s=> s.Features.Any(f=> DesiredFeatures.Contains(f.name)));

Я знаю Intersect может помочь, и вот как я использовал его:

var q = Stores.Where(s => s.Features.Intersect<Feature>(DesiredFeatures));

Это где я застрял , Intersect хочет объект Feature, то, что мне нужно для пересечения, находится в Feature.Name.

Цель состоит в том, чтобы получить ObservableCollection, где каждый Магазин имеет все желаемые характеристики.

Спасибо!

ответ

1

мне нужно использовать LINQ, чтобы дать мне результаты только магазины, которые имеют все Желаемые характеристики.

Другими словами, каждая желаемая функция должна иметь соответствующую функцию хранилища.

Я не вижу, как в этом случае может помочь Intersect. Прямой перевод указанных выше критериев к LINQ, как это:

var q = Stores.Where(s => 
    DesiredFeatures.All(df => s.Features.Any(f => f.Name == df)) 
); 

Более эффективным способом может быть использование GroupJoin для проведения матча:

var q = Stores.Where(s => 
    DesiredFeatures.GroupJoin(s.Features, 
     df => df, sf => sf.Name, (df, sf) => sf.Any() 
    ).All(match => match) 
); 

или Except для проверки несовпадающих элементов:

var q = Stores.Where(s => 
    !DesiredFeatures.Except(s.Features.Select(sf => sf.Name)).Any() 
); 
+0

Спасибо, Иван, GroupJoin был идеальным решением и сделал трюк. –

2

Вы почти сделали то, что вам нужно. Небольшим уточнением было бы обменять DesiredFeatures и s.Features.

var q = Stores.Where(s => DesiredFeatures.All(df => s.Features.Contains(df))); 

Это означает, что вы берете только те магазины, где желаемые функции все содержатся в функциях магазина.

+0

очень близко, но мой 'df' является строкой, а не функцией. Думаю, я мог бы реорганизовать, чтобы сделать DesiredFeatures List , но это похоже на бандаж –

1

Отправляясь на вашей идее пересекаются, единственный способ, которым я считал, что делает эту работу был с помощью Select получить Store.Features (List<Feature>) в виде списка имен (Feature List<string>) и пересекаются, что с DesiredFeatures.

Обновлено Ответ:

var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures).Any()); 

или

var q = Stores.Where(s => DesiredFeatures.Intersect(s.Features.Select(f => f.Name)).Any()); 

Старый Ответ (если DesiredFeatures является List<Feature>) :

var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures.Select(df => df.Name)).Any()); 
+0

Очень близко, но DesiredFeatures - это «Список ». Если я изменю 'DesiredFeatures.Select (df => df)', я получаю тот же результат, что и моя первоначальная попытка. –

+0

О, извинения. Я не видел, что DesiredFeatures - это список строк. Является ли это списком имен функций или какой-либо другой информации? Вероятно, вы должны указать это и в своем вопросе. – Kody

+0

Да, я знаю, что это похоже на мой первый запрос, но f.name в предикате происходит из функций. Я пытаюсь реорганизовать список , так как он может быть менее сложным –

0

Две вещи, которые вы хотите, чтобы ваш код выполнял.

var q = Stores.Where(s=> s.Features.All(f=> DesiredFeatures.Contains(f.name)) && 
         s.Features.Count() == DesiredFeatures.Count()); // Incude Distinct in the comparison if Features list is not unique 
  • Убедитесь, что каждый особенностью является DesiredFeature
  • магазин содержит все необходимые функции.

Код выше предполагает уникальность Features коллекции, а также DesiredFeatures, изменять код, как указано в строке комментария, если это не так

Смежные вопросы