Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Select followed by Where result in two iterations over the IEnumerable?

Let say I have

IEnumerable<int> list = new int[] { 1, 2, 3 };
List<int> filtered = list.Select(item => item * 10).Where(item => item < 20).ToList();

The question is are there two iterations or just one.

In other words, is that equivalent in performance to:

IEnumerable<int> list = new int[] { 1, 2, 3 };
List<int> filtered = new List<int>();
foreach(int item in list) {
    int newItem = item * 10;
    if(newItem < 20)
        filtered.Add(newItem);
}
like image 634
Petar Ivanov Avatar asked Nov 02 '11 22:11

Petar Ivanov


People also ask

Is IEnumerable an iterator?

IEnumerable is the return type from an iterator. An iterator is a method that uses the yield return keywords. yield return is different from a normal return statement because, while it does return a value from the function, it doesn't “close the book” on that function.

Which is faster IEnumerable or List?

IEnumerable is conceptually faster than List because of the deferred execution. Deferred execution makes IEnumerable faster because it only gets the data when needed. Contrary to Lists having the data in-memory all the time.

Should I use IQueryable or IEnumerable?

So if you working with only in-memory data collection IEnumerable is a good choice but if you want to query data collection which is connected with database `IQueryable is a better choice as it reduces network traffic and uses the power of SQL language.

Why should I use IEnumerable?

IEnumerable is best to query data from in-memory collections like List, Array etc. IEnumerable doesn't support add or remove items from the list. Using IEnumerable we can find out the no of elements in the collection after iterating the collection. IEnumerable supports deferred execution.


2 Answers

There is a single iteration over the collection performed when you call the .ToArray method so both should be equivalent. .Select is a projection and .Where is a filter, both expressed as expression trees on the original dataset.

Could be easily proven:

public class Foo: IEnumerable<int>
{
    public IEnumerator<int> GetEnumerator()
    {
        yield return 1;
        Console.WriteLine("we are at element 1");
        yield return 2;
        Console.WriteLine("we are at element 2");
        yield return 3;
        Console.WriteLine("we are at element 3");
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main()
    {
        var filtered = new Foo()
            .Select(item => item * 10)
            .Where(item => item < 20)
            .ToList();
    }
}

when run prints the following:

we are at element 1
we are at element 2
we are at element 3
like image 80
Darin Dimitrov Avatar answered Nov 16 '22 22:11

Darin Dimitrov


In Linq to Objects WHERE and SELECT do not iterate over the enumerable. The calling code enumerates it when it does a foreach on the query or ToList or ToArray(), etc.

In Linq to SQL there is no iteration what so ever. When you do ToList or ToArray() the query is executed by database. Depending on the type of query db could look up indexes or do a table scan.

like image 24
Muhammad Hasan Khan Avatar answered Nov 16 '22 22:11

Muhammad Hasan Khan