Use .Any instead of .Count

I am amazed by how many developers use IEnumerable<T>.Count() when they should use IEnumerable<T>.Any().

How many times have you seen/written this:

if (collection.Count() > 0)
{
    // Now that we know we have some elements,
    // let's do something meaningful
}

There are (at least) 3 basic flaws with this approach:

1. Highly inefficient
2. Semantical implications
3. Infinite loops

1. It is highly inefficient (average case).

First, the IEnumerable<T>.Count() extension method checks if the underlying type implements ICollection<T>. If it does, you have escaped the performance hell. The IEnumerable<T>.Count() method will check the ICollection<T>.Count property to check how many elements the collection has. This is done in O(1).

But if the underlying collection does not implement ICollection<T>, the IEnumerable<T>.Count() will have to iterate through all the items to see how many there are. Such operation works in O(N).

2. Any is semantically better than Count

Let’s be real – no programmer will be the least baffled about what exactly Count() > 0 does. At least I hope so. However, the fact remains that Any() method better conveys the intention of the code.

Think for a moment about a natural language (English in this example). You don’t hear a professor say after his lecture: "Is the number of questions you have greater than zero?" More likely he would say something like "Do you have any questions?" He is not interested in how many, but if any at all. That semantic difference is simply better expressed with Any().

3. You may get stuck in an infinite loop

An iterator can be a generator. Take a look at this code:

private static IEnumerable<bool> oscillations()
{
    bool state = false;

    while (true)
    {
        yield return state;
        state = !state;
    }
}

This function returns false, true, false, true, false, true, etc. Forever. Or until you stop iterating. If you are iterating over such “collection” with a foreach loop, you can break the loop whenever you want. But you have no control of the loop if you call Count() on such IEnumerable. Thus the following line will never complete.

int oscCount = oscillations().Count();

Using Any() would work, however.

The chance that you will create and use an infinite generator is extremely small. While one can see the way they could be useful, this behavior alone should probably make you think twice before using them. But what if you have a third-party library? You never know what you’re dealing with.

Conclusion.

If you don’t need the exact count of your collection, but only want to know if it has any elements at all, go with Any(). You simply can’t lose if you do.

Leave a Reply

Your email address will not be published. Required fields are marked *