0

I have a list of class Products:

class Products
{
    public string Name { get; set; }
    public string Size { get; set; }
    public string ProductId { get; set; }
    public string Category { get; set; }
}

I would like to use one TextBox to search through any matching products utilizing a wildcard value. This would return me a list of items where all values in the search string are found somewhere in the four properties listed above.

As of now, I'm using string[] values = searchText.Split("*".ToCharArray) to seperate the values of the search string into an array of strings (based on an asterisk wildcard). From there, I get stumped, since I want to search for all values of the search string in all properties of the class.

I tried to figure it out using a complex LINQ statement, but I have not been able to figure it out how to make this work. I don't know how to build a Where statement when I don't know how many values I'm going need to test against my four properties.

5
  • 1
    When you say "wildcard search", what would the input look like? What wildcard characters do you want to support? Also, when you say, "all values in the search string", do you mean they may have more than one term they're searching for? Some sample input and expected output may be helpful. Commented May 22, 2019 at 23:44
  • What I'd like is to be able to accept a search value like "hem*per" and that would return items where both "hem" and "per" could be found anywhere in the four values of a given Product object. This would return a product where the name could be "Hemerocallis" and the category could be "Perennial". Commented May 22, 2019 at 23:48
  • @LiquidDrummer - So, based on that description, you're not doing a "wildcard" search. You're simply using a * as a delimiter to break up the individual strings you're looking for. Commented May 22, 2019 at 23:54
  • @Enigmativity - Yes . . . sorry, the wildcard verbiage is a bit misleading. Sorry about that. Commented May 23, 2019 at 0:06
  • @LiquidDrummer - Am I right that you just want * to delimit your keywords? Commented May 23, 2019 at 0:08

2 Answers 2

2

So, if you're breaking search up into separate keywords, using * as the delimiter, which you've described in the comments, then this is how you do it:

var products = new List<Products>()
{
    new Products()
    {
        Name = "theo frederick smith",
        Size = "",
        ProductId = "",
        Category = "brown",
    }
};

var searchText = "fred*brown";

var splits = searchText.Split("*".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

var results =
    products
        .Where(p => splits.All(s =>
            p.Name.Contains(s)
            || p.Size.Contains(s)
            || p.ProductId.Contains(s)
            || p.Category.Contains(s)));

That matches the input.

Alternatively, if you really want a wildcard search, such as "fred*smith" (meaning that any one field must contain "fred" followed by zero or more characters and followed by "smith"), then this works:

var products = new List<Products>()
{
    new Products()
    {
        Name = "theo frederick smith",
        Size = "",
        ProductId = "",
        Category = "brown",
    }
};

var searchText = "fred*smith";

var wildcard =
    new Regex(
        String.Join(".*",
            searchText
                .Split('*')
                .Select(x => Regex.Escape(x))));

var results =
    products
        .Where(p => new []
        {
            p.Name, p.Size, p.ProductId, p.Category
        }.Any(x => wildcard.IsMatch(x)));
Sign up to request clarification or add additional context in comments.

1 Comment

@RufusL - Just some sample data. The first code block used it.
1

Naively, you could write

products.Where(x=>x.Name.Contains(search) 
                  || x.Size.Contains(search) 
                  || x.ProductId.Contains(search) 
                  || x.Category.Contains(search))

You would be better off putting that logic in your Product class.

So you would have:

class Products
{
    public bool Contains(string term) {
              return Name.Contains(search) || Size.Contains(search) || 
              ProductId.Contains(search) || Category.Contains(search)
    }

    public string Name { get; set; }
    public string Size { get; set; }
    public string ProductId { get; set; }
    public string Category { get; set; }
}

And then simply products.Where(x=>x.Contains(search))

You could also use reflection to get all the property names and do a for each on each string and check for Contains.

2 Comments

How does this handle the "wildcard" requirement?
It doesn't, when I wrote it, it just showed as delimited on a wildcard - so in that case, the author would have had to loop through each term until one was found.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.