65.9K
CodeProject is changing. Read more.
Home

Finding Items in a Collection that Match one of...

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (6 votes)

Oct 20, 2016

CPOL

1 min read

viewsIcon

19145

Use LINQ to get the members of a collection that match the members of another collection

Introduction

Recently, I have answered a couple of Quick Answers where the user wanted a list of items that match a condition from another collection (similar to SQL's IN operator. The trick to solving this is reversing the order of the operands in the Where Linq extension from the norm.

Using the Code

The normal structue of a Where predicate follows the pattern:

myCollection.Where(item=>item.Property matches value)

where Property is the property you want to match to a particular value using whatever operator or method is appropriate to return the required result. However, what if value is a collection of values? The trick to extracting your items is basically to reverse the conditional statement, and, depending on the way the match is made, optionally apply an Any, All, or Contains method to the values collection. So the basic pattern becomes:

myCollection.Where(item=>values.Any(value=>value matches item.Property));

Some Examples

Problem

Get all items from List1 that are one of the items in List2. Comparison should be case-insensitive. This is basically the same as a standard SQL IN clause:

SELECT Field FROM TABLE WHERE Field IN (value1, value2,....valueN)

Solution

List<string> values = {value1, value2...valueN};
var results = table
    .Select(rec=>rec.field)
    .Where(field=>values.Contains(field, StringComparer.CurrentCultureIgnoreCase));

Problem

Get all items where the inventory_code is prefixed with one of a set of standard prefixes(strings).

Solution

string[] prefixes = {"N01", "N02", "M01", "M02" };
var results = inventoryList
    .Where(item=>prefixes.Any(prefix=>item.inventory_code.StartWith(prefix)));

Problem

Get paragraphs that contain all of the pre-defined words.

Solution

This solution performs the trick twice. Upon separating out each paragraph, the Where is issued with the SearchWords array as the LHS of the condition. It then issues the All condition for each word in SearchWords with the words in the paragraph as the LHS of the condition.

string[] searchwords = {....};
string[] paragraphs = {
    "The quick brown fox jumps over the lazy dog.",
    "The quick brown fox jumps over the lazy cat.\nNotice the substitution of 'cat' for 'dog'.",
    "The quick brown fox jumps over the lazy cat." };
string[] searchWords = { "FOX", "DOG" };
char[] wordDelimiters = { ' ', ',', '.', ';', ';','\n', '"', '\'' };
var results = paragraphs.Where(paragraph => searchWords
  .All(word => paragraph.Split(wordDelimiters, StringSplitOptions.RemoveEmptyEntries)
  .Contains(word, StringComparer.CurrentCultureIgnoreCase)));

As evidenced by these examples, the concept of using a pre-defined collection as the LHS operand in a Where albeit seeming a little unnatural, can be a useful tool.