Learning to Love The Linq Any() Method
There is a Linq extension method that I managed to miss for a long time: Any(). It’s fairly natural to miss this, I believe, since the paradigm of collections tends to be fully ingrained in our way of doing things. That is, if I want to see if any members of a collection match a certain criteria, I do something like this:
bool doesDirectExist = false;
foreach (var myFeature in features)
doesDirectExist |= myFeature.ID == "Direct";
I cycle through my collection of features looking for “Direct” and, if I find one, the boolean flag is flipped to true. Otherwise, it remains false. If I wanted to get a little more efficient, I could break if the flag got flipped or do this in a two-condition while loop.
This hearkens back to the days of storing values in simple arrays in older languages than C# and before the existence of IEnumerable, foreach() and other such constructs. For those of us who learned this way, iterate and check is quite natural.
But then, Linq came along and gave us the handy-dandy Where(Func<T, bool>) extension method:
bool doesDirectExist = features.Where(f => f.ID == "Direct").Count() > 0;
This accomplishes the same thing, but as a one-liner. That in and of itself is nice, but it gets doubly nice when you consider that the short-circuit optimization is built in to the implementation of Where(). Where() returns an enumeration, which is more or less a collection (yes, yes, I understand that it’s not really, but that’s how we tend to regard it), so the natural seeming thing to do is query it for a count. I remained content with this for a long time, until I discovered Any().
I can achieve the same thing with:
bool doesDirectExist = features.Where(f => f.ID == "Direct").Any();
This is a lot more semantically clear. I’m not really interested in an integer comparison — I want to know whether there are any features matching my criteria. It may not seem important, but cutting down on noise in the code is very important for promoting readability since, in the excellent words of Grady Booch, “clean code reads like well-written prose.” In other words, this code says “do any features exist where the id is equal to ‘direct’?” as opposed to “is the count of features with id equal to ‘direct’ greater than zero?” The former reads a lot more conversationally than the latter.
But, we have one more improvement to make here:
bool doesDirectExist = features.Any(f => f.ID == "Direct");
In terms of prose-like, conversational reading, this is pretty much still “do any features exist where the id is equal to ‘direct’?” The “where” is implied here, I would say. But, now the code is more succinct, and there is one fewer method call. Brevity is generally good.
I’ve been using this for a while now, but I still encounter old code of mine where I wasn’t aware of this little gem and I encounter code written by others who aren’t aware of it. So, if you’re one of those people, be aware of it now and use in good health!
By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.
Thank you for this tip. I usually used FirstOrDefault, and in case the item wasn’t found i return false.
Now I can use only one line.
Thanks for reading, and glad if you liked. It’s good you mentioned this, actually. Because now that I think about it, I would also sometimes do what you describe (FirstOrDefault() and then null check). That was more something I would do before I discovered the where/count trick because that was also a one liner, but I did that as well. And, that was a source of minor concern to me over the course of time since I usually find it to be a smell in my code if I have a few different ways of solving the same problem.
Thanks for pointing this out. I cringe when I see
if( someEnumerable.Count() > 1 ) { blah… }
being used instead of
if( someEnumerable.Any()) { blah… }
Definitely one to have handy!
Hey Eric, good to see you around. I think this is one of those things where once you first see it, there’s an “oh, awesome” and then you never go back.
Thanks. Our mutual friend pointed me towards your blog, and I’ve been slowly reading my way back through the posts. I’ve really been enjoying them.
[…] DaedTech Professional Software Engineering Skip to content HomeServicesConsultingHome AutomationPortfolioProjectsDatabase TechnologiesMS AccessMySQLOraclePostgreSQLSQL ServerFrameworksContent Management System (CMS)Embedded SystemsRealtimeSpringWPFMarkup LanguagesCSSHTMLXAMLXMLOperating SystemsLinuxWindowsProgramming LanguagesAssemblyCC#C++JavaJavascriptPHPVBAVisual BasicTesting FrameworksJUnitMS TestNUnitVersion ControlClear CaseCVSGitSource SafeSubversionTFSPublicationsAdditional InformationAboutSocial MediaPrivacy PolicyBlog ← Learning to Love The Linq .Any() Method […]
Oh, it’s love at first sight! I think I discovered it early this year and started pointing it out in code reviews to share the love!