Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using LINQ where(lamdaexp).First and First(lambdaexp)

Tags:

c#

lambda

linq

Is there any difference in the below two approaches? I am getting same output but I am trying to understand which is right and effective

approach 1:

Product product12 = products.Where(p => p.ProductID == 12).First();

approach 2:

Product prod12 = products.First(p => p.ProductID == 12);
like image 857
hanuma Avatar asked Jan 07 '23 22:01

hanuma


1 Answers

(I assume that you are using Linq to .Net)
Firstly let's look at their source codes:

Here is Where():

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    if (source == null) 
        throw Error.ArgumentNull("source");
    if (predicate == null) 
        throw Error.ArgumentNull("predicate");
    if (source is Iterator<TSource>) 
        return ((Iterator<TSource>)source).Where(predicate);
    if (source is TSource[]) 
        return new WhereArrayIterator<TSource>((TSource[])source, predicate);
    if (source is List<TSource>) 
        return new WhereListIterator<TSource>((List<TSource>)source, predicate);
    return new WhereEnumerableIterator<TSource>(source, predicate);
}

And here is First()

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

And let's find what does each code do:

  1. products.First(p => p.ProductID == 12);

Based on source code of the First() we can say, First() will iterate over collection, and will stop iteration when it finds first item in a collection which mets the criteria.

  1. products.Where(p => p.ProductID == 12).First();

First it will create iterator in Where method where elements meet the criteria. Then, again it will add get the first elemnt to that iterator. And, again will returm the first element as soon as it finds it.

As an additional note, LINQ uses deferred execution in some methods. And it has some relationship with the result of your question.

Deferred execution is a pattern of the execution model by which the CLR ensures a value will be extracted only when it is required from the IEnumerable-based information source. When any Linq operator uses the deferred execution, the CLR encapsulates the related information, such as the original sequence, predicate, or selector (if any), into an iterator, which will be used when the information is extracted from the original sequence using ToList method or ForEachmethod or manually using the underlying GetEnumerator and MoveNext methods in C#.

And, the question is. Which one is faster?


The main point is that, Where().First is quicker than First. in case of List and Array. Otherwise, First() will be faster. Here is the detailed exlpanation in @Akash Kava answer.

Let's pay an attention to Where() implementation. It will return WhereListIterator() if your collection is List, but First() will just iterate over source. And in my opinion they have made some speed up in the implementation of WhereListIterator. And after this we are calling First() method which takes no predicate as input and only will iterate on filtered collection.

Also, as I understand, The Where iterator avoids indirect virtual table call, but calls iterator methods directly. And, this is the reason of this speed-up.

like image 179
Farhad Jabiyev Avatar answered Jan 20 '23 13:01

Farhad Jabiyev