Any() versus Count()

by KodefuGuru 7. December 2009 18:20

Jimmy Bogard brought to my attention today that I had been doing something wrong all along. I’ve been using Count() on my enumerations when I should have been using Any(). I’ve even done this in a presentation I’ve been giving the past few months. This is from Mash Up.

if (businesses.Count() == 0)
{
    return PartialView("Message", new MessageViewData { Header = "No Results Found", 
        Message = "We didn't find anything near your location." });
}
else
{
    return View(new ResultsViewData { Geolocation = geolocation, Businesses = businesses });
}

The problem, as Jimmy pointed out in his twitter feed, is that Count() iterates the entire enumeration (unless it is an ICollection<T>, via a commenter with Reflector). Any(), on the other hand, will return after it hits the first one. This should be rewritten.

if (businesses.Any())
{
    return View(new ResultsViewData { Geolocation = geolocation, Businesses = businesses });
}
else
{
    return PartialView("Message", new MessageViewData { Header = "No Results Found", 
        Message = "We didn't find anything near your location." });
}

The reason I used Count() is quite simple: I was too used to using the Count property on List<T>. I never bothered to look if there was a better way of doing this.

Just as Count() can take a parameter as a predicate, so can Any(). This is useful in that it prevents an unnecessary Where to be chained up.

if (primes.Any(p => primes.Contains(p + 4)) )
{
    Console.WriteLine("Prime numbers provided contains Cousin primes");
}

The scenario you should use Count() is when you need to know the actual count.

var cousins = primes.Count(p => primes.Contains(p + 4));
Console.WriteLine("{0} primes provided have cousins", cousins);

Use the method that fits the job. I know I will be paying more attention to Any() from now on.

Tags: , ,

Kodefu

Comments

12/7/2009 6:23:52 PM #

Kevin Griffin

Excellent tip.  This one is going into my mental toolbox.

Thanks a lot for posting.

Kevin Griffin United States

12/7/2009 8:21:59 PM #

Jonathan

I concur with Kevin. Really interesting to know...especially in terms of performance. :}

Jonathan United States

12/7/2009 11:07:08 PM #

Jason Smith

Not meaning to be pedantic, but whats the point of doing:

if (something)
{
  return Foo ();
}
else
{
  return Bar ();
}

instead of:

if (something)
{
  return Foo ();
}
return Bar ();

I see lots of programmers doing the former and the latter really never seems to be seen. I understand coding standards but surely the else is just eating up lines and horizontal space (which I hate seeing wasted).

Jason Smith United States

12/7/2009 11:48:17 PM #

Ryan

Jason:  The simple answer is readability.  Since there is an inherent else, if you represent it in your code other people reading your code will have an easier time.

Remember: not everyone who goes through the code in a big project is going to be experienced.

Ryan United States

12/8/2009 5:49:06 AM #

Not a Community Champion

This article is not accurate.

Linq checks to see if the collection implements a few different interfaces and uses thier Count property if it is available before iterating the collection.

Have a dig around using Reflector and see for yourself.

Not a Community Champion United Kingdom

12/8/2009 7:46:05 AM #

Jeremy

"Not a Community Champion" is right. See the code of the extension method below:

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;
    }
    int num = 0;
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            num++;
        }
    }
    return num;
}


Jeremy France

12/8/2009 7:51:13 AM #

Tommy Carlier

"Not a Community Champion": what if the subject does not implement ICollection<T>? What if it's a LINQ-to-SQL query? Any() would call MoveNext() just once, Count() would call MoveNext() repeatedly.

Tommy Carlier Belgium

12/8/2009 9:16:00 AM #

curlyfro

resharper refactors this for you where it can.

gotta love resharper.

curlyfro United States

12/8/2009 10:28:59 AM #

chris

Not a Community Champion: you are correct. Fixing.

chris United States

12/8/2009 11:05:07 AM #

Adde

You have exactly the same problem in SQL where people are doing COUNT(*) > 0 instead of using EXISTS.

Also, why are you using if/else to do simple conditional returns? Declarative beats imperative any day:

return business.Any()
  ? View(new ResultsViewData { Geolocation = geolocation, Businesses = businesses })
  : PartialView("Message",
                new MessageViewData { Header = "No Results Found",
                                      Message = "We didn't find anything near your location." });

Adde Sweden

12/8/2009 1:48:59 PM #

Jason Young

Actually, knowing the internals now makes this a bit more complicated. You want to use .Count() if you know it's actually a list. However, if you know it's a list, you should use the .Count property on that list and avoid the whole issue. I would use .Count() if I was expecting the IEnumerable to be a list more often than not.

Does anyone know if .Any() will check the count if called on a collection? If so, that would always be optimal.

Jason Young United States

12/8/2009 1:55:03 PM #

chris

Adde, my first instinct is that the ternary operator with that much text is unreadable. However, I will do a comparison in VS to see. Perhaps I need to shift my style even further from imperative programming.

chris United States

12/8/2009 1:58:21 PM #

Jason Young

I just checked the source for .Any(). It does NOT use .Count if it's a list.

Jason Young United States

12/8/2009 1:58:56 PM #

chris

Jason, the compiled version of Any() attempts to MoveNext() on the Enumerator. If it succeeds, it returns true.

chris United States

12/8/2009 2:34:52 PM #

chris

It checks Count if it's an ICollection<T>, which List<T> implements. Check the reflected code Jeremy posted. You can see this in Reflector yourself.

chris United States

12/8/2009 2:37:06 PM #

Justin James

Wow, sounds to me like an old dinosaur like myself, who would just iterate through the collection and stop the iteration the moment I find what I need, is going to have the guaranteed performance edge, at the expense of a few extra lines of code. Lines of code which, I may add, the junior developers or folks who don't know LINQ so well will actually understand, too. Smile

Sometimes what is "readable" to one person (ie: declarative syntax) is utter nonsense to others (ie: declarative syntax). If "readability" is your goal, imperative stuff is understandable by *all* while declaritive only makes sense to those who "get" it. Until more developers become well versed in declarative syntax (which could be another 5 - 10 years, look at how slowly OO truly took root, and most folks *still* don't do it anywhere near correct), I consider it to be a way of reducing readability for the typical co-worker.

All too often, the use of LINQ suffers from the "all too clever" syndrome, for better or for worse.

J.Ja

Justin James United States

12/8/2009 5:56:12 PM #

Mahmoud

It's like "Exists" and "Count" in SQL

Mahmoud Egypt

12/9/2009 10:02:54 AM #

Not a Community Champion

I think this depends on the context you are using the Count()/Any() method in.

If you are consuming a interface where you don't know what the underlying type for IEnumerable is then Any() would be the fastest but it still needs to get the enumerator, which has the overhead of creating a new object. It's not a black and white scenario. The only time I think this would ever make any difference is in a system where performance is vital and it is critical that you don't wastefully iterate the collection, i.e. a system you would not develop on the .net framework.

However, there is a more important point here than the internals of 2 extension methods. That point is that a "community champion" posted a blog verbatim without first checking the content because another someone else told him somthing and he accepted it as fact. Other developers are adding this to their "mental toolbox" and accepting it as fact because the community champion bloged it. This is not just a problem for inexperienced devs, this article was pointed out to me by our senior architect because he heard us discussing using the Count() method. Just beware that you check everything you read in a blog before you go spouting it to your colleagues and you look stupid when someone blows it away.

Not a Community Champion United Kingdom

12/9/2009 5:39:17 PM #

Chris

Not a Community Champion: you pointed out that there is an optimization for ICollection<T> built into the implementation of Count(), and I added a correction to the blog post in response. Even books make mistakes and issue errata, and this happens to be a blog without technical reviewers (besides the readers). I don't use reflector on every class to check for optimizations.

It still stands to reason that Any() is more correct than Count() in the context of checking for whether an IEnumerable is empty since the purpose of Any() is to check for emptiness. From the documentation on Any(): "Determines whether a sequence contains any elements" and "Parameters - source - The IEnumerable<> to check for emptiness."

There is no need to use scare quotes around "community champion." That award was for my contributions to the community by organizing and speaking at user groups.

Chris United States

12/10/2009 1:54:54 PM #

Sean Kearon

Not a Community Champion - Chris is correct that Any() should be preferred over Count() for existence checks.  This is a very useful best practise and a very worthy post.  I fail to see why you are trying to cast fear, uncertainty and doubt over a what is an informative and technically correct article!

Sean Kearon United Kingdom

12/11/2009 9:28:10 AM #

Ben Taylor

@J.Ja:  "Until more developers become well versed in declarative syntax".  People will not become well versed if you don't use it.  I find it better to use Linq where appropriate and then mentor other people on the team that don't understand it.  It does not take long and all appreciate having more knowledge and additional options in their locker.  IMO writing lines of unecessary code is a waste of an employers money (as most devs wont be using R# live templates or similar either) and dismissing it as "all to clever" is not really accurate.

Ben Taylor United Kingdom

12/11/2009 1:09:08 PM #

Mike Griffin

To Justin James, from one old timer to another, very, very well said. I couldn't have said it better.

Mike Griffin United States

12/13/2009 1:07:36 PM #

Muhammad Mosa

Although I always work with Any in similar cases like you mentioned in your post! now I know why I am using it!
Of course using ICollection or IEnumerable won't change my behavior of keep using Any over Count when appropriate, at the end I treat them all as IEnumerable.

Thank you Chris. Good tip!

Muhammad Mosa Egypt

12/22/2009 8:50:20 AM #

Jarno Peschier

Excellent point. This is similar to peshir.blogspot.com/.../...hether-ienumerable.html but now I know about Any() - Ahum... - I will be using that instead of something like my NotEmpty extension method on my sequences when I'm using LINQ.

Jarno Peschier Netherlands

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.0.0
Theme by Mads Kristensen

Whois KodefuGuru

Chris Eargle

Chris Eargle
.NET Community Champion

LinkedIn Twitter Technorati Facebook

MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er


World Map

RecentComments

Comment RSS

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010