DaveDev
DaveDev

Reputation: 42175

Is testing for .Any() elements more or less efficient than trying to iterate an empty list?

Which is more efficient - to attempt to iterate an empty list, or to test if there are any items in the list before attempting to iterate?

For example, first get an empty list of things:

var listOfThings = GetZeroThings(); // this returns 0 things

is it less efficient to attempt to execute this:

foreach (var thing in listOfThings)
{

}

or should I test whether there are any items? e.g.

if (listOfThings.Any())
{
    foreach (var thing in listOfThings)
    {

    }   
}

Upvotes: 0

Views: 71

Answers (3)

Ian
Ian

Reputation: 30813

My simple test shows that the one with Any is slower:

[2016-04-18 03:01:55.900 UTC] Without Any: 254 ms
[2016-04-18 03:01:56.266 UTC] With Any: 363 ms

The code is below (may not be reproducable since you do not have my component logBox, but is included to show the fairness of the test):

IEnumerable<int> listOfThings = new List<int>();
logBox.GetTimeLapse();
for (int i = 0; i < 10000000; ++i)
    foreach (var thing in listOfThings)
        Console.WriteLine("Do something!");
logBox.WriteTimedLogLine("Without Any: " + logBox.GetTimeLapse());
logBox.GetTimeLapse();
for (int i = 0; i < 10000000; ++i)
    if (listOfThings.Any())
        foreach (var thing in listOfThings)
            Console.WriteLine("Do something!");
logBox.WriteTimedLogLine("With Any: " + logBox.GetTimeLapse());

Which I think is making sense because of the present of extra Any while your foreach (var thing in listOfThings) alone would have already done the checking for you anyway.

Edit:

Additional note by Jonathan Allen which I think is worth included: The line if (listOfThings.Any()) (1) allocates memory and (2) makes a virtual dispatch call. The line foreach (var thing in listOfThings) does neither.

Upvotes: 2

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101680

If you look at Any's source:

public static bool Any<TSource>(this IEnumerable<TSource> source) 
{
        if (source == null) throw Error.ArgumentNull("source");
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            if (e.MoveNext()) return true;
        }
        return false;
}

You can see that all it's doing is to call GetEnumerator on the source collection and call MoveNext method. The foreach will do exactly the same for an empty collection so, calling Any before foreach is redundant. But I believe it won't make any significant affect in terms of performance and I think using Any before foreach makes the code more readable.

Upvotes: 5

Rob
Rob

Reputation: 27357

You need to profile it. It's really impossible to give you an answer. That being said, checking Any() looks like it can cause issues.

For example:

void Main()
{
    var listOfThings = GetThings();
    if (listOfThings.Any())
    {
        foreach (var item in listOfThings)
        {
            Console.WriteLine("A");
        }
    }
}

public IEnumerable<int> GetThings()
{
    Thread.Sleep(10000);
    yield return 1;
}

Assuming the first element is expensive to get, you're doing the work twice. It entirely depends on how your collection behaves. As above, you need to profile your own circumstances.

Just by looking at it, it seems like Any() will always be redundant, as it grabs the enumerator anyway.

Upvotes: 1

Related Questions