methuselah methuselah - 29 days ago 8
C# Question

LINQ query to check if array contains search term

I have the following LINQ query that processes a string and I want to change it to deal with an array. How can I do it?

This is the LINQ query at the moment (where

FilteredString
is a string). It works perfectly fine:

var xFiltered = Services.Where(x =>
x.Name.ToUpper().Contains(xFilteredString.ToUpper() ||
x.Hosts.Select(y => y.Name)
.Any(y => y.ToUpper().Contains(xFilteredString.ToUpper()))));


However, I am struggling to get it to work in this case (the following code doesn't work) where I am checking if an array contains particular value:

var xFilteredArray = xFilteredString.Split(',')
var xFilteredArrayToUpper = xFilteredArray.Select(s => s.ToUpperInvariant());

var xFiltered = Services(Where x =>
x.Name.ToUpper().Any(y => xFilteredArrayToUpper.All(x.Name.Contains) ||
x.Hosts.Select(y => y.Name)
.Any(y => y.ToUpper().Contains(xFilteredArrayToUpper.All(x.Name.Contains)))));


How can I fix it?

Answer

If I understand correctly then this is how. You want to chech for each item in the filterArray if any of it's values is contained in the x.Name or y.Name:

var filterArray = xFilteredString.Split(',')
                                 .Select(s => s.ToUpperInvariant())
                                 .ToList();

var result = Services.Where(x => 
                 filterArray.Any(filter => x.Name.ToUpper().Contains(filter) ||
                 x.Hosts.Any(y => filterArray.Any(filter => y.Name.ToUpper().Contains(filter))));

I think a more readable way will be to use the query syntax:

var filterArray = xFilteredString.Split(',')
                                 .Select(s => s.ToUpperInvariant())
                                 .ToList();

var result = from x in Services
             let upperName = x.Name.ToUpper() 
             where filterArray.Any(filter => upperName.Contains(filter)) ||
                   x.Hosts.Select(host => host.Name.ToUpper())
                          .Any(host => filterArray.Any(filter => host.Contains(filter)))
             select x;

The use of the let and the Hosts.Select that I don't have in the method syntax is so the ToUpper is performed once for each value checked and not once for each value in the filterArray too

Also I decided to chain the different operations for creating the filterArray. I think it is clearer that way

Comments