Can't figure out why this IEnumerable is giving this answer

The answer to the following code is 5

Can someone explain why this is? If you were int d1 = x.Current

to replace with d1 = x.Current

and declare d1

the while loop above, the answer would be 2 , and I understand why it is, but I don't know why it is 5 otherwise.

IEnumerable<int> num = new []{10,11,12,13,14,15,16};
IEnumerable<int> div = new [] {2,3,5};

var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();

while(x.MoveNext()){
    int d1 = x.Current;
    lazy = lazy.Concat(num.Where(s=>s % d1 == 0));
}

int count = lazy.Distinct().Count();
Console.WriteLine("{0}",count);

      

EDIT: Here is a snippet that gives you answer 2.

IEnumerable<int> num = new []{10,11,12,13,14,15,16};
IEnumerable<int> div = new [] {2,3,5};

var lazy = Enumerable.Empty<int>();
var x = div.GetEnumerator();
int d1;

while(x.MoveNext()){
    d1 = x.Current;
    lazy = lazy.Concat(num.Where(s=>s % d1 == 0));
}

int count = lazy.Distinct().Count();
Console.WriteLine("{0}",count);

      

+3


source to share


2 answers


(Peter beat me to the beat, but I was halfway there when his answer came up, so I'll post it anyway.)

You can get more information on the differences using the code. The instrumentation in the lambda expression is what provides critical insight:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Baseline.");
        Test1();
        Console.WriteLine("Modified.");
        Test2();
    }

    static void Test1()
    {
        IEnumerable<int> num = new[] { 10, 11, 12, 13, 14, 15, 16 };
        IEnumerable<int> div = new[] { 2, 3, 5 };

        var lazy = Enumerable.Empty<int>();
        var x = div.GetEnumerator();

        while (x.MoveNext())
        {
            int d1 = x.Current;
            Console.WriteLine("d1 = " + d1);
            lazy = lazy.Concat(num.Where(s => {bool result = s % d1 == 0; Console.WriteLine("s = " + s + ", d1 = " + d1); return result;}));
            Console.WriteLine("lazy has " + lazy.Count());
        }

        Console.WriteLine("Evaluating lazy.Distinct().Count()");        
        int count = lazy.Distinct().Count();
        Console.WriteLine("{0}", count);
    }

    static void Test2()
    {
        IEnumerable<int> num = new[] { 10, 11, 12, 13, 14, 15, 16 };
        IEnumerable<int> div = new[] { 2, 3, 5 };

        var lazy = Enumerable.Empty<int>();
        var x = div.GetEnumerator();
        int d1;

        while (x.MoveNext())
        {
            d1 = x.Current;
            Console.WriteLine("d1 = " + d1); 
            lazy = lazy.Concat(num.Where(s => {bool result = s % d1 == 0; Console.WriteLine("s = " + s + ", d1 = " + d1); return result;}));
            Console.WriteLine("lazy has " + lazy.Count());
        }

        Console.WriteLine("Evaluating lazy.Distinct().Count()");
        int count = lazy.Distinct().Count();
        Console.WriteLine("{0}", count);
    }
}

      



After "Evaluating lazy.Distinct (). Count ()" is printed, you will notice two things that might surprise you.

First, this evaluation requires rerunning the lambda expression that was declared in the loop. It's easy, but wrong, to think of "lazy" as a collection of integers. This is actually a function to create a set of integers, so it needs to re-work this function to count individual items.

Secondly, you will notice that the d1 values ​​differ between the two estimates. In the first case, d1 is 2, and in the second case, d1 is 5. The reason for this is, as Peter Dunyho pointed out, that declaring d1 outside the loop allows you to keep the value it had at the end of the loop (so you have 5, the last value in the sequence div), wherease declaring it in a loop requires re-evaluating it (so you have 2, the first element in the div sequence).

+4


source


This is due to the delayed execution of the lambda expression in the lazy.Concat(num.Where(s=>s % d1 == 0))

.

When you declare a variable inside a loop, each instance of the anonymous method gets its own variable. But when you declare a variable outside of the loop, they all have the same variable, and of course that variable value only has one value (the final value assigned in the loop) when the lambda expression is finally executed here:



int count = lazy.Distinct().Count();

      

Moral of the story: Beware of using captured variables. They are often difficult to reason about and should be used carefully.

+4


source







All Articles