6

I don't understand the order of execution in the following code. Here the numbers that satisfied the first Where clause are (4, 10, 3, 7), and the numbers that satisfied the second Where clause are 2 and 1, after that we have function Aggregate that subtract them and make one element from both.

My question is what is the flow of execution here - (1) Where is executed with c/3 > 0 for all the elements and after that (2) Where or (1) first clause is executed for one element and its passed to (2) and from there to aggregate - when I print the values I cannot get value of x to be 28 on paper with both approaches also I cannot debug linq statement. Thanks for any help in advance.

var ints = new int[] { 2, 4, 1, 10, 3, 7 };

var x = ints
    .Where(c => c / 3 > 0)               <-- (1)
    .Select(s2 => s2 + ints
        .Where(c => c / 3 == 0)          <-- (2)
        .Aggregate((f, s) => f - s))     
    .Sum();
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    *"i cannot debug linq statement"* - yes you can. If breakpoints are hard to follow you can make lambdas (`c => ...`) into code blocks (`c => { ... }`) and add debug output (`Debug.WriteLine`). – Sinatr May 16 '19 at 07:51
  • @Sinatr It dosen't allow me to put { } brackets where you say... btw its not hard to follow its just get executed in one step or it allows me to put breakpoint only on select and the variable it dosen't help. –  May 16 '19 at 07:54
  • @BorisBorovski the brackets from @Sinatr like `c => {…}` should be written as `c => { return …}` – arlan schouwstra May 16 '19 at 08:02
  • @Rafalon Thanks. But i still dont get it in first step(1) number 4 is taken and on the second step(2) number 2 because 2/3 == 0 and aggregate must perform 4 - 2 but my logic its not right can you explain me. –  May 16 '19 at 08:02
  • @BorisBorovski Second selects 2 and 1 and you perform aggregate on these two : 2-1 = 1 (check my answer below) – Rafalon May 16 '19 at 08:04

2 Answers2

6

The same statement can be written as follows:

var ints = new int[] { 2, 4, 1, 10, 3, 7 };

var x = ints
    .Where(c =>
        {
            Console.WriteLine($"1 Where for number: {c}");
            return c / 3 > 0;
        }) //< --(1)
    .Select(s2 => s2 + ints
        .Where(c =>
        {
            Console.WriteLine($"2 Where for number: {c}");
            return c / 3 == 0;
        }) // < --(2)
        .Aggregate((f, s) =>
        {
            Console.WriteLine($"Aggregate: f: {f} s: {s}");
            return f - s;
        }))
    .Sum();

In this every shorthand lambda expression can be written as a complete anonymous method with a method body. You just need to use the { .. } parentheses. Inside them you can write multiple statements. If you check the documentation for Where you can see that it expects (in your case) a Func<int, bool> as input parameter. That means that you pass an int inside and return a bool. This is why you need to write the explicit return statement as I did: return c / 3 > 0;

If you now insert there a debug output to the console you will get a written proof and insight into the execution of the entire code compartment.

The resulting output looks like the following:

1 Where for number: 2 1 Where for number: 4 2 Where for number: 2 2 Where for number: 4 2 Where for number: 1 Aggregate: f: 2 s: 1 2 Where for number: 10 2 Where for number: 3 2 Where for number: 7 1 Where for number: 1 1 Where for number: 10 2 Where for number: 2 2 Where for number: 4 2 Where for number: 1 Aggregate: f: 2 s: 1 2 Where for number: 10 2 Where for number: 3 2 Where for number: 7 1 Where for number: 3 2 Where for number: 2 2 Where for number: 4 2 Where for number: 1 Aggregate: f: 2 s: 1 2 Where for number: 10 .... ....

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
4
ints
    .Where(c => c / 3 == 0)     // (2,1)
    .Aggregate((f, s) => f - s) //  2-1

evaluates to 1

Therefore your query can be switched to:

var ints = new int[] { 2, 4, 1, 10, 3, 7 };

var x = ints
    .Where(c => c / 3 > 0) // (4,10,3,7)
    .Select(s2 => s2 + 1)  // (5,11,4,8)
    .Sum();                // 28
Rafalon
  • 4,450
  • 2
  • 16
  • 30
  • 1
    Thank you a lot guys. Btw @Mong Zhu i didn't realize this is anonymous method that makes LINQ a lot clearer maybe i must start to read the docs in depth. –  May 16 '19 at 08:06
  • Yes now it makes sens. Thanks. –  May 16 '19 at 08:10