Reputation: 1917
I have a list of Stores (of type ObservableCollection<Store>
) and the Store
object has a property called Features ( of type List<Feature>
). and the Feature
object has a Name property (of type string
).
To recap, a list of Stores that has a list of Features
I have a second collection of DesiredFeatures (of type List<string>
).
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures. So far, I've only been able to come up with a query that gives me an OR result instead of AND.
Here's what that looks like:
var q = Stores.Where(s=> s.Features.Any(f=> DesiredFeatures.Contains(f.name)));
I know Intersect
can help, and here's how I've used it:
var q = Stores.Where(s => s.Features.Intersect<Feature>(DesiredFeatures));
This is where I'm stuck, Intersect wants a Feature
object, what I need to intersect is on the Feature.Name.
The goal is to end up with an ObservableCollection where each Store has all of the DesiredFeatures.
Thank you!
Upvotes: 2
Views: 192
Reputation: 205589
I need to use LINQ to give me results of only the stores that have all the DesiredFeatures.
In other words, each desired feature must have a matching store feature.
I don't see how Intersect
can help in this case. The direct translation of the above criteria to LINQ is like this:
var q = Stores.Where(s =>
DesiredFeatures.All(df => s.Features.Any(f => f.Name == df))
);
A more efficient way could be to use a GroupJoin for performing the match:
var q = Stores.Where(s =>
DesiredFeatures.GroupJoin(s.Features,
df => df, sf => sf.Name, (df, sf) => sf.Any()
).All(match => match)
);
or Except to check for unmatched items:
var q = Stores.Where(s =>
!DesiredFeatures.Except(s.Features.Select(sf => sf.Name)).Any()
);
Upvotes: 1
Reputation: 16956
Two things you want your code to perform.
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
Code above assumes uniqueness in Features
collection as well as DesiredFeatures
, modify code as stated in comment line if this is not right
Upvotes: 0
Reputation: 965
Going on your intersect idea, the only way I thought of making this work was by using Select
to get the Store.Features (List<Feature>
) as a list of Feature Names (List<string>
) and intersect that with DesiredFeatures.
Updated Answer:
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures).Any());
or
var q = Stores.Where(s => DesiredFeatures.Intersect(s.Features.Select(f => f.Name)).Any());
Old Answer (if DesiredFeatures is a List<Feature>
):
var q = Stores.Where(s => s.Features.Select(f => f.Name).Intersect(DesiredFeatures.Select(df => df.Name)).Any());
Upvotes: 1
Reputation: 4236
You've almost done what you need. A small refine would be to swap DesiredFeatures
and s.Features
.
var q = Stores.Where(s => DesiredFeatures.All(df => s.Features.Contains(df)));
It means take only those stores where desired features are all contained in features of the store.
Upvotes: 2