Suppose I have some strings:
string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
What is the difference between:
string startsWithO = strings.First(s => s[0] == 'o');
And:
string startsWithO = strings.Where(s => s[0] == 'o').First();
Since Where() is deferred it shouldn’t slow down the execution, right?
The performance penalty of using
.Where(filter).First()rather than.First(filter)will usually be very small.However, they’re not the same –
Wheregenerates a new iterator thatFirstcan simply take one element of, whereasFirst(filter)can microoptimize by using just one loop and a direct return wheneverfiltermatches.So while both approaches have the same semantics and both execute the
filterequally often (only as often as necessary), usingFirstwith afilterparameter doesn’t need to create an intermediate iterator object and probably avoids some very simple method calls on that iterator too.In other words, if you’re executing such code millions of times, you will see a slight performance difference – but nothing huge; I would never worry about it. Whenever that tiny performance difference actually matters you’re much better off just writing the (very simple) foreach-with-if statement that’s equivalent and avoiding the extra calls and object allocations inherent in LINQ – but remember that this is a microoptimization you’ll rarely need.
Edit: Benchmark demonstrating the effect:
This takes 0.78 seconds:
But this takes 1.41 seconds:
Whereas plain loops are much faster (0.13 seconds):
Note that this benchmark only shows such extreme differences because I have a trivial filter and a very short non-matching prefix.
Based on some quick experimentation, the difference seems largely attributable to the details of which codepath gets taken. So, for array’s and
List<>s the first variant is actually faster, likely to do special-casing in.Wherefor those types thatFirstdoesn’t have; for custom iterators, the second version is a tiny bit faster, as expected.Summary:
.Where(...).First()is roughly as fast as.First(...)– don’t bother choosing one or the other as an optimization. In general.First(...)is very slightly faster but in some common cases it is slower. If you really need that microoptimization then use plain loops which are faster than either.