25

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.

usefulBee
  • 9,250
  • 10
  • 51
  • 89
Lrayh
  • 1,281
  • 2
  • 13
  • 15

6 Answers6

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).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Does this still apply if tags is a string? – Lrayh May 20 '14 at 17:31
  • 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. – Jon Skeet May 20 '14 at 17:42
  • 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. – Lrayh May 20 '14 at 18:18
  • 1
    @Lrayh: how did you expect us to guess that that's what you meant? And is this EF, Linq to Sql, something else? – Jon Skeet May 20 '14 at 18:20
  • Sorry, I didn't think of it when I first created the question. Using EF. Added that part to the original question earlier. – Lrayh May 20 '14 at 18:33
  • 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.. – Harry Jun 15 '18 at 17:10
  • @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)? – Jon Skeet Jun 15 '18 at 18:41
  • `var list = new List {"this is a big bat and etc bla bla bla", "test123 123 123"};` `var words = new List { "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. – Harry Jun 16 '18 at 07:30
  • @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. – Jon Skeet Jun 16 '18 at 10:42
  • im not saying change something. Im pointing out that this case doesnt work for all strings. cheers. – Harry Jun 16 '18 at 10:54
7

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)));
aleonj
  • 163
  • 2
  • 7
2

like this:

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

 var result = query.Where(x => list.Contains(x.tags));
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • 2
    `Contains` does not accept a sequences of items as it's parameter – Servy May 20 '14 at 15:44
  • 2
    the OP states that x.tags is a string, although I am still unsure of the question – happygilmore May 20 '14 at 21:02
  • 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". – TPG Aug 16 '18 at 05:40
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)
happygilmore
  • 3,008
  • 4
  • 23
  • 37
1
  var t = new List<string> { "a", "b", "c" };

var y = "a b d";

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

Cos
  • 552
  • 1
  • 9
  • 16
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