How to use Linq to check if a list of strings contains any string in a list
Asked Answered
L

6

26

I'm constructing a linq query that will check is a string in the DB contains any of the strings in a list of strings.

Something like.

query = query.Where(x => x.tags
                   .Contains(--any of the items in my list of strings--));

I'd also like to know how many of the items in the list were matched.

Any help would be appreciated.

Update: I should have mentioned that tags is a string not a list. And I am adding on a couple more wheres that are not related to tags before the query actually runs. This is running against entity framework.

Laspisa answered 20/5, 2014 at 15:38 Comment(2)
So is x.tags a list too?Flied
Could you give some sample input and output? It's likely that you'll want to use PredicateBuilder, but the "know how many of the items were matched" might further complicate things.Magna
F
31

EDIT: This answer assumed that tags was a collection of strings...

It sounds like you might want:

var list = new List<string> { ... };
var query = query.Where(x => x.tags.Any(tag => list.Contains(tag));

Or:

var list = new List<string> { ... };
var query = query.Where(x => x.tags.Intersect(list).Any());

(If this is using LINQ to SQL or EF, you may find one works but the other doesn't. In just LINQ to Objects, both should work.)

To get the count, you'd need something like:

var result = query.Select(x => new { x, count = x.tags.Count(tag => list.Contains(tag)) })
                  .Where(pair => pair.count != 0);

Then each element of result is a pair of x (the item) and count (the number of matching tags).

Flied answered 20/5, 2014 at 15:41 Comment(10)
Does this still apply if tags is a string?Laspisa
No, you'd need to change it - I was assuming that as tags is plural, it's a collection of tags. Why is it called "tags" if it's a single value? Or is it a comma-separated value? That would make things more complicated.Flied
Its a string of comma separated values. Was hoping to be able to just check to see if any of the stings in the list were anywhere in the string of , separated values.Laspisa
@Lrayh: how did you expect us to guess that that's what you meant? And is this EF, Linq to Sql, something else?Flied
Sorry, I didn't think of it when I first created the question. Using EF. Added that part to the original question earlier.Laspisa
This doesnt work if the list has short words and the string where you need to check if it contains words is a long paragraph kind of thing..Thirty
@Harry: In what way? I'm confused by exactly what situation you're describing, and how you believe this code wouldn't work. Or is it due to the lack of clarity of the question (as per the first line of this answer, explaining that this is where "tags" is a list of strings, not a single string)?Flied
var list = new List<string> {"this is a big bat and etc bla bla bla", "test123 123 123"}; var words = new List<string> { "bat","hello","whatever","etc"}; var item = list.Where(x => x.Any(tag => words.Contains(tag)); word will never contain tag because it is a short word and you are quering a list of long sentences.Thirty
@Harry: The question starts with: "I'm constructing a linq query that will check is a string in the DB contains any of the strings in a list of strings." The string "bat" isn't in that list of strings you've presented. As soon as you get into substrings, it all becomes a lot more complicated - would you need to split by word first, or would "ig" be valid in your example? I think I've answered the question as it was originally written pretty reasonably, and I'm not going to change it to the more complex version that you're suggesting.Flied
im not saying change something. Im pointing out that this case doesnt work for all strings. cheers.Thirty
R
8

I've done something like this before:

var myList = new List<string>();
myList.Add("One");
myList.Add("Two");

var matches = query.Where(x => myList.Any(y => x.tags.Contains(y)));
Reynaud answered 30/8, 2016 at 8:25 Comment(2)
what is y? where did you define that? Isn't X the search term you're looking for?Weitzman
@softwareisfun that's a lambda function. query has items, and therefore x is a query item. mylist has items, therefore y is a mylist item. Check out the .Where and .Any extensions for in Linq library. Thanks aleonj, this is great ^Heyerdahl
B
2

I am not quite sure from your question if x.tags is a string or list, if it is a list Jon Skeet's answer is correct. If I understand you correctly though x.tags is a string of strings. If so then the solution is:

list.Any(x => x.tags.IndexOf(x) > -1)

to count them do

list.Count(x => x.tags.IndexOf(x) > -1)
Beery answered 20/5, 2014 at 21:0 Comment(0)
T
1

like this:

List<string> list = new List<string>();
list.Add("One");
list.Add("Two");

 var result = query.Where(x => list.Contains(x.tags));
Teleprinter answered 20/5, 2014 at 15:40 Comment(3)
Contains does not accept a sequences of items as it's parameterPolk
the OP states that x.tags is a string, although I am still unsure of the questionBeery
This works if x.tags matches exactly to the list. How about if I want to have the LIKE effect? Said will return as long as tags is "One milk", "One fridge"... Currently it will only return if the tags is "One".Veii
E
1
  var t = new List<string> { "a", "b", "c" };

var y = "a b d";

var res = y.Count(x => t.Contains(x.ToString()));

Endorsee answered 20/5, 2014 at 15:48 Comment(1)
No, I'm pretty certain this is not what the OP is asking for.Magna
S
0

I faced a similar problem recently and here's how I managed to work it out:

var list = [list of strings];
if (list != null && list.Any())
{
    queryable = queryable.Where(x => x.tags != null);
    var tagQueries = new List<IQueryable<WhateverTheDbModelIs>>();
    foreach (var element in list)
    {
        tagQueries.Add(queryable.Where(x => x.tags.Contains(element)));
    }
    IQueryable<WhateverTheDbModelIs> query = tagQueries.FirstOrDefault();
    foreach (var tagQuery in tagQueries)
    {
        query = query.Union(tagQuery);
    }
    queryable = queryable.Intersect(query);
}

probably not the best option but something a less experienced developer can understand and use

Salpa answered 7/6, 2021 at 7:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.