简体   繁体   中英

Use Linq to return all objects in a list where the object's sub-object-list property contains all values of an int list

I have a list of products. Each product contains an attribute list. The attribute list has 2 properties, optionId, and attributeSetId. I first start with an int list of filtered optionId's. I want to return all products that have optionIds that contain all the items in the list of filtered optionId's

class Product
{
   int Id;
   string Label;
   List<Attributes> attributes
}

class Attribute
{
   int optionId,
   int attributeSetId,
}

List<Products>() products;
List<>() filteredOptionIDs;
filteredOptionIds.Add(5);
filteredOptionIds.Add(34);
filteredOptionIds.Add(3456);

I need to return all products that have all the optionId's in the filteredOptionIds list

Edit -- Robert McKee example with Except() is the only one that worked for me.

var filteredProducts = products
  .Where(p=>!filteredOptionIds.Except(p.attributes.Select(a=>a.optionId)).Any());

If all else fails, this will work:

var filteredProducts = products.AsQueryable();
foreach(var option in filteredOptionIds)
  filteredProducts = filteredProducts.Where(r=>r.attributes.Select(att=>att.optionId).Contains(option));

This works by just repeatedly filtering down the results once for each option. You can also use an expression builder. There are so many different ways of accomplishing this task, the best approach really depends on what else you need/want to do with the query and what source it is coming from (database vs IEnumerable).

Another approach would look like this, but it may confuse some database LINQ providers, so test it before use:

var filteredProducts = products
  .Where(p=>!filteredOptionIds.Except(p.attributes.Select(a=>a.optionId)).Any());

This should also work:

var filteredProducts = products
    .Where(p=>filteredOptionIds.All(opt=>p.attributes.Any(att=>att.optionId==opt));

So, you need to make a where clause on products. The criteria is that all attribute.optionId should be present in the filteredOptionIDs. So you could use the contains from the filteredOptionIds. Then use the All so they all must be present.

You might try something like: (pseudo code)

var filteredProducts = products
    .Where(prod => prod.attributes.All(att => filteredOptionIds.Contains(att.optionId));

Even faster is the use of the !Any:

var filteredProducts = products
    .Where(prod => !prod.attributes.Any(att => !filteredOptionIds.Contains(att.optionId));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM