Tys
Tys

Reputation: 3610

Implement Linq search query for n number of keywords and AND / OR option

I have a textbox that takes free text as input for a search and I have a LINQ query that I want to extend with this type of search.

The input could be something like "big blue car" and that should result in a query that searches for titles that contain all these words.

There is also an option to switch to "any word" instead of "all words".

What is the best/easiest way to add this to my LINQ query?

The query now looks like

from b in books
where b.InStore == true && b.Price > 10 && title.Contains()...at this point i want to add the text search. 
select b

Upvotes: 2

Views: 1094

Answers (2)

Adam Mihalcin
Adam Mihalcin

Reputation: 14478

I would first split the query and the title into words, and then check for containment. A rough cut is

string[] queryParts = query.Split(' ');

books.Where(b => b.InStore)
    .Where(b => b.Price > 10)
    .Where(b => queryParts.Any(part => b.Title.Split(' ').Contains(part)))

for the any query, and

string[] queryParts = query.Split(' ');

books.Where(b => b.InStore)
    .Where(b => b.Price > 10)
    .Where(b => queryParts.All(part => b.Title.Split(' ').Contains(part)))

for the all query.

We have to split the title into words because the default String.Contains method looks for any substring match, which means that

"ABC DEF".Contains("A")

returns true, even though for this purpose we don't want it to.

Note that both these solutions assume that words are always delimited by spaces, which isn't true in general. Your user could type tabs in between words, use quotes to delimit groups of words (e.g. "New York"), and so on.

Upvotes: 0

gdoron
gdoron

Reputation: 150303

I strongly reccommend you to do it with two queries!

But take a look at this, isn't it cool?

var searchAll = true;
var words = List<string>{"big", "blue", "car"};

from b in books
where (...) (searchAll && words.All(x => title.contains(x))) ||
            (!searchAll && words.Any(x => title.Contains(x)))
select b

But you really should make it with two different queries.

Upvotes: 1

Related Questions