Spidey
Spidey

Reputation: 3023

Filter a list by a string array

I have a WinForms app in which I want to use a text box to take in a search query (e.g. mens black tshirt) and then filter a list of objects based on this search query.

The list of objects are orders objects. Each order object had several properties such as gender, size, colour etc.

If I get an array of strings by splitting the search query by the Space character, what is the best way to search for every item in this string array against every property in every order object in the list and return those that match all the strings in the string array?

For example if I search for "kids black medium", I only want to return orders that are kids AND black AND medium, so I would not want just black orders or just kids order etc.

Upvotes: 2

Views: 4580

Answers (2)

sloth
sloth

Reputation: 101072

Given the following Order class:

class Order
{
    public string Size {get; set;}
    public string Gender {get; set;}
    public string Colour {get; set;}
    public string Type {get; set;}

    // List of "searchable" properties
    public IEnumerable<string> GetTags()
    {
        return new []{Size, Gender, Colour, Type};
    }
}

a simple approach could look like:

var list = new []
{
    new Order {Size = "large", Gender = "women", Colour = "red", Type = "tshirt"},
    new Order {Size = "large", Gender = "men", Colour = "black", Type = "tshirt"},
    new Order {Size = "medium", Gender = "kids", Colour = "black", Type = "tshirt"},
    new Order {Size = "medium", Gender = "kids", Colour = "black", Type = "shorts"},
    new Order {Size = "medium", Gender = "men", Colour = "black", Type = "tshirt"}
};

var searchString = "kids black medium";
var searchValues = searchString.Split(new []{" "}, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray();

var result = from order in list 
             let tags = order.GetTags()
             where searchValues.All(s => tags.Any(t => t == s))
             select order;

result now contains

enter image description here

You could also use Intersect or a HashSet to compare the search values/tags, but without further information of the requirements All/Any is a good-enough solution IMHO.

Upvotes: 3

Ryszard Dżegan
Ryszard Dżegan

Reputation: 25434

Try the following:

class Item
{
    public bool Gender { get; set; }
    public int Color { get; set; }
    public string Type { get; set; }

    public string[] GetKeyWords()
    {
        // Return properties as array of key words.
        // You can cache the result for future use.
        return default(string[]);
    }
}

Now if you have the list of items and array of strings (keywords), you can write the following query:

var matches = from item in items
              let itemKeyWords = item.GetKeyWords()
              where keyWords.All(k => itemKeyWords.Any(c => c == k))
              select item;

Upvotes: 1

Related Questions