70

What is the difference between these two Linq queries:

var result = ResultLists().Where( c=> c.code == "abc").FirstOrDefault();
// vs.
var result = ResultLists().FirstOrDefault( c => c.code == "abc");
  • Are the semantics exactly the same?
  • Iff sematically equal, does the predicate form of FirstOrDefault offer any theoretical or practical performance benefit over Where() plus plain FirstOrDefault()?
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
SOFextreme
  • 731
  • 1
  • 5
  • 6

4 Answers4

42

Either is fine.

They both run lazily - if the source list has a million items, but the tenth item matches then both will only iterate 10 items from the source.

Performance should be almost identical and any difference would be totally insignificant.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 6
    No difference is **insignificant** - 1ms over a thousand items called by 500 users per day add up to a lot of time. – TheGeekZn Jan 23 '14 at 06:36
  • 12
    @NewAmbition - You're talking less than one percent of a day. That's not a lot of time. The difference I get when I compare the two approaches is working out to be 1ms for over 150,000 items (not 1ms for each item, it's 1ms for all 150,000). So based on that your 500 x 1,000 items query that's about 0.003ms per day. It's not significant. – Enigmativity Jan 23 '14 at 09:32
  • 9
    I thought the word would be italic, not bold :| You're right, although I was using a bloated example. I didn't intend to sound douchey, just that sometimes the tiny performance hits can add up :) – TheGeekZn Jan 23 '14 at 11:36
  • 1
    My code editor detects Where(X)+First() and suggests writing First(X) instead. – hugo Aug 21 '19 at 09:09
  • 0.003ms - you wanted to write 3ms I suppose. And "one percent of a day" is a really bad metric. If you have 100 random approx 3 sec lags over your 8 hour day, it is only 1% of the time, but you would like to throw the computer out of the window at the end of the day. – Antonín Lejsek Sep 22 '19 at 02:25
15

The second one. All other things being equal, the iterator in the second case can stop as soon as it finds a match, where the first one must find all that match, and then pick the first of those.

Dave C
  • 429
  • 3
  • 9
  • 6
    I believe that `Where` results in a "projection" or "lazy enumerable sequence" (while there may be slightly more overhead, it does not need to run through any more elements from `ResultList`, see ending note), but I choose the latter in most cases.... in the case of LINQ2SQL or similar, I have no idea what the query generator would do. –  Nov 09 '11 at 01:21
  • 10
    Not true - The chaining behaviour of LINQ means that it iterates lazily. For both approaches if the first item is a match they won't go any further. – Enigmativity Nov 09 '11 at 01:39
  • 5
    @Enigmativity: that is not true for all Linq providers. While it is true for Linq to Objects, providers based on SQL underpinnings must return (or at least process) the entire set before returning the first object. The bottom line is that regardless of what underlying optimizations certain providers give, since you can't rely on it being true in all cases, it is better to go for what would conceptually always give correct behavior, all other things being equal. – Dave C Nov 09 '11 at 01:49
  • 4
    @DaveC - You would expect the most basic provider to figure out that `FirstOrDefault` should return `TOP 1` items, surely? – Enigmativity Nov 09 '11 at 02:20
  • 1
    You make an excellent point. In practical terms the two would be equivalent, but I would still err on the side of using a method that kills two birds with one stone rather than chaining multiple methods together. We can logically assume that anyone implementing a custom provider would think to implement FirstOrDefault as a TOP 1, but there's no guarantee of that. (To be fair, there is also no guarantee that FirstOrDefault with a predicate would behave itself either.) – Dave C Nov 09 '11 at 04:58
  • 1
    Not to put too fine a point on it, but I recall my first foray into Linq to Entities and my surprise that it didn't support Single() or SingleOrDefault(). It seemed (and still seems) like such a simple operation, but for whatever reason it wasn't even implemented. So I guess my point is, in absence of full information about the system, and faced with two otherwise equivalent options, I would pick the simpler one. – Dave C Nov 09 '11 at 05:01
  • 16
    I started getting "The wait operation timed out." using `Where(query).FirstOrDefault()` on a large dataset. When I changed it to `FirstOrDefault(query)` I stopped seeing it; so maybe there's something to this answer. Regardless, the code is slightly nicer to read. – Chad Hedgcock Feb 25 '15 at 13:59
5

Nice discussion, all the above answers are correct.

I didn't run any performance test, whereas on the bases of my experience FirstOrDefault() sometimes faster and optimize as compare to Where().FirstOrDefault().

I recently fixed the memory overflow/performance issue ("neural-network algorithm") and fix was changing Where(x->...).FirstOrDefault() to simply FirstOrDefault(x->..).

I was ignoring the editor's recommendation to change Where(x->...).FirstOrDefault() to simply FirstOrDefault(x->..).

So I believe the correct answer to the above question is

The second option is the best approach in all cases

Ihtsham Minhas
  • 1,415
  • 1
  • 19
  • 31
1

Where is actually a deferred execution - it means, the evaluation of an expression is delayed until its realized value is actually required. It greatly improves performance by avoiding unnecessary execution.

Where looks kind of like this, and returns a new IEnumerable

foreach (var item in enumerable)
{
    if (condition)
    {
        yield return item;
    }
}

FirstOrDefault() returns <T> and not throw any exception or return null when there is no result

Akhilesh Kamate
  • 775
  • 7
  • 13
  • Amazing point. Looking at benchmarks comparing the two syntaxes over large collections of size n, it can be seen that 'Where([predicate]).FirstOrDefault() has significantly better performance and a constant slope as n increases. As compared to the alternative, whose slope varies wildly. –  Jul 03 '22 at 02:27
  • While it is correct that execution of `Where()` is deferred, you're omitting the fact that, in this question, it is immediately followed by a call to `FirstOrDefault()`, for which execution is immediate. So, execution gets delayed for all of an instant until `FirstOrDefault()` needs it performed, anyways, which isn't any kind of optimization. `FirstOrDefault()` could certainly be implemented the same way you've shown here, too (with `return item;` substituted for `yield return item;`). – Lance U. Matthews Jul 03 '22 at 03:30