2

Is there a better linq query to see if a list contains any item in another list than the following:

results.Where(r => r.Categories.Intersect(submittedCategories).Count() > 0)

where r.categories is the list of categories the result is in and submittedCategories i a list of categories the user want to filter on

Pete
  • 57,112
  • 28
  • 117
  • 166

4 Answers4

6

I would use Enumerable.Any instead of Enumerable.Count:

results.Where(r => r.Categories.Intersect(submittedCategories).Any())

Method Count() has optimization for sources which implement ICollection (it simply returns Count property value of collection). But result of Enumerable.Intersect will be IEnumerable<T> so in this case Count() will iterate over all set:

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)    
        throw Error.ArgumentNull("source");

    ICollection<TSource> is2 = source as ICollection<TSource>;
    if (is2 != null)    
        return is2.Count;

    ICollection is3 = source as ICollection;
    if (is3 != null)    
        return is3.Count;

    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext()) // you will fall into this case
           num++; 
    }
    return num;
}

It means that full intersection should be built from both collections to know total count of items in result. And only then value will be compared with zero.

Any() will stop iterating just after first item will be found without finding all items which intersect.

public static bool Any<TSource>(this IEnumerable<TSource> source)
{
    if (source == null)    
        throw Error.ArgumentNull("source");

    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (enumerator.MoveNext())        
            return true;        
    }
    return false;
}

Another benefit - Any() shows your intent better.

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
5

Is there a better linq query to see if a list contains any item in another list

If you are looking for any item matching then use Enumerable.Any instead of Count()

results.Where(r => r.Categories.Intersect(submittedCategories).Any())

You may see where Any would be better for Count(): Which method performs better: .Any() vs .Count() > 0?

Community
  • 1
  • 1
Habib
  • 219,104
  • 29
  • 407
  • 436
3

You can also use Any directly without Intersect:

results.Where(r => r.Categories.Any(submittedCategories.Contains))
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 1
    It worth noting that you are not simply removing usage of `Intersect` - you are *replacing* it with usage of `Contains`. And here comes important thing: Any+Contains has complexity O(N*M). Intersect+Any requires additional memory, but has complexity O(N+M) – Sergey Berezovskiy Apr 14 '14 at 16:11
1

Try using Any() method.

Any receives a Predicate. It determines if any element in a collection matches a certain condition.

Source: Dotnetperls

Harry
  • 3,031
  • 7
  • 42
  • 67