Question

If I know there is only one matching item in a collection, is there any way to tell Linq about this so that it will abort the search when it finds it?

I am assuming that both of these search the full collection before returning one item?

var fred = _people.Where((p) => p.Name == "Fred").First();
var bill = _people.Where((p) => p.Name == "Bill").Take(1);

EDIT: People seem fixated on FirstOrDefault, or SingleOrDefault. These have nothing to do with my question. They simply provide a default value if the collection is empty. As I stated, I know that my collection has a single matching item.

AakashM's comment is of most interest to me. I would appear my assumption is wrong but I'm interested why. For instance, when linq to objects is running the Where() function in my example code, how does it know that there are further operations on its return value?

Was it helpful?

Solution

Your assumption is wrong. LINQ uses deferred execution and lazy evaluation a lot. What this means is that, for example, when you call Where(), it doesn't actually iterate the collection. Only when you iterate the object it returns, will it iterate the original collection. And it will do it in a lazy manner: only as much as is necessary.

So, in your case, neither query will iterate the whole collection: both will iterate it only up to the point where they find the first element, and then stop.

Actually, the second query (with Take()) won't do even that, it will iterate the source collection only if you iterate the result.

This all applies to LINQ to objects. Other providers (LINQ to SQL and others) can behave differently, but at least the principle of deferred execution usually still holds.

OTHER TIPS

I think First() will not scan the whole collection. It will return immediatelly after the first match. But I suggest to use FirstOrDefault() instead.

EDIT:

Difference between First() and FirstOrDefault() (from MSDN):

The First() method throws an exception if source contains no elements. To instead return a default value when the source sequence is empty, use the FirstOrDefault() method.

Enumerable.First

Substitue .Where( by .SingleorDefault( This will find the first and only item for you.

But you can't do this for any given number. If you need 2 items, you'll need to get the entire collection.

However, you shouldn't worry about time. The most effort is used in opening a database connection and establishing a query. Executing the query doesn't take that much time, so there's no real reason to stop a query halfway :-)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top