aj100
aj100

Reputation: 48

Linq Take doing extra passes through collection

I was trying to better understand the function composition in linq and to that effect I wrote code like this:

var x = Enumerable.Range(1, 10);

var result = x.Select(AddFive)
              .Where(FilterEvens)
              .Take(1);

result.ToList(); 

Where the AddFive and FilterEvens methods are defined as below:

int AddFive(int n)
{
    Console.WriteLine("Adding five");
    return n+5;
}

bool FilterEvens(int n)
{
    Console.WriteLine("Filtering evens");
    return n%2 == 0;
}

If I take 1 and run it, I get the following result which is what I would expect:

Adding five
Filtering evens

If I try to take 2 or 5 however, I get:

Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens

And:

Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens
Adding five
Filtering evens

In other words it looks like the Take is going further than it needs to in the collection. Is this is a bug? (I'm guessing it's not.) If it's not, is there some good reason why it's implemented this way?

Upvotes: 1

Views: 52

Answers (1)

Selman Genç
Selman Genç

Reputation: 101701

Take is not going further. It keeps iterating until it finds as many numbers as you want.Since you have a filtering, not all numbers are returned because some of them do not satify the condition.So, you see the message for each number projected by Select and filtered by Where.

For example in case of Take(2):

Select returns 6 to where - it's returned 
Select returns 7 to where - not returned
Select returns 8 to where - returned

That's why you see the message three times

Upvotes: 4

Related Questions