Where is lambda vs first lambda

Suppose I have a few lines:

string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; 

What's the difference between:

 string startsWithO = strings.First(s => s[0] == 'o'); 

and

 string startsWithO = strings.Where(s => s[0] == 'o').First(); 

Since Where () is delayed, this should not slow down execution, right?

+8
source share
3 answers

Performance .Where(filter).First() when using .Where(filter).First() rather than .First(filter) will usually be very small.

However, they do not match - Where generates a new iterator, which First can simply take one element, while First(filter) can micro-optimize using only one loop and direct return whenever filter matches.

So, although both approaches have the same semantics and both perform filter same way (only as often as necessary), using First with the filter parameter does not require creating an intermediate iterator object and, possibly, avoids some very simple method calls on this iterator.

In other words, if you execute such code millions of times, you will see a small difference in performance - but nothing huge; I would never worry about that. Whenever this tiny performance difference actually matters, it’s much easier for you to write a (very simple) foreach-with-if statement that is equivalent and avoids the extra calls and object distributions inherent in LINQ β€” but remember, this is microoptimization, which you will rarely need to.

Edit: Test showing effect:

It takes 0.78 seconds:

 for(int i=0;i<10*1000*1000;i++) Enumerable.Range(0,1000).First(n=> n > 2); GC.Collect(); 

But it takes 1.41 seconds:

 for(int i=0;i<10*1000*1000;i++) Enumerable.Range(0,1000).Where(n=> n > 2).First(); GC.Collect(); 

While simple loops are much faster (0.13 seconds):

 long bla = 0; for(int i=0;i<10*1000*1000;i++) for(int n=0;n<1000;n++) if(n > 2) { bla+=n; break; } GC.Collect(); Console.WriteLine(bla);//avoid optimizer cheating. 

Please note that this test only shows such extreme differences, because I have a trivial filter and a very short mismatching prefix.

Based on some quick experiments, the difference seems to be largely explained by the details by which the encoding takes place. Thus, for an array and List<> first option is actually faster, most likely it will make a special wrapper in .Where for those types that First does not have; for custom iterators, the second version is slightly faster, as expected.

Summary:

.Where(...).First() about as fast as .First(...) - you should not choose one or another optimization. In the general case, .First(...) very slightly faster, but in some common cases it is slower. If you really need this microoptimization, use simple loops that are faster than either.

+12
source share

There are no differences.

Call Where first returns an iterator that is not used until its first start.

If the predicate does not match any elements, then the same InvalidOperationException is thrown.

The only difference is the verbosity of the code, therefore. First without. Should be preferred

+1
source share

In the specific case, by calling First and Where on string[] , the called methods are extension methods Enumerable.Where and Enumerable.First .

Enumerable.Where does the following:

 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { // null checks omitted if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate); //the rest of the method will not execute } 

and the WhereArrayIterator constructor does only:

 public WhereArrayIterator(TSource[] source, Func<TSource, bool> predicate) { this.source = source; this.predicate = predicate; } 

Therefore, nothing is done here except to create an iterator.

The first First method without a predicate does this:

 public static TSource First<TSource>(this IEnumerable<TSource> source) { //null check IList<TSource> list = source as IList<TSource>; if (list != null) { //this branch is not taken as string[] does not implement IList<string> if (list.Count > 0) return list[0]; } else { //this is actually the WhereArrayIterator from before using (IEnumerator<TSource> e = source.GetEnumerator()) { if (e.MoveNext()) return e.Current; } } throw Error.NoElements(); } 

However second First does it

 public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { //null checks foreach (TSource element in source) { if (predicate(element)) return element; } throw Error.NoMatch(); } 

Which in the case of an array is as fast as direct linear access.
In a nutshell, this means that calling First(predicate) in the array will be somewhat faster, but a small, but still determinable factor. This may not match the lists and, of course, will not contain IQueryable objects, which are a completely different story.

However, this is micro-optimization for the worst. If this is not done millions of times, it will not save too many seconds. Even when I know it now, I will still use everything that is clearer to read and understand.

+1
source share

All Articles