-3

File contains some string, like:

abc 4 2

def 1 1 1

Gh 0

Have some LINQ function, details of this function are not so important

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; });
}

this function does not output anything to the console. Why?

Uwe Keim
  • 36,867
  • 50
  • 163
  • 268

2 Answers2

7

You have to materialize the sequence to make it run:

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; })
        .ToList();
}

On a related note, it is advised to never cause side-effects in LINQ expressions. If this code is for debugging purposes, then it's fine. But if you plan to leave it for future use, then I'd advise you to remove the Console.Write from inside the LINQ expression.

The reason why we should not cause side effects in expressions is that most of the LINQ operators are lazy-evaluated. This, in turn, is done to improve performance by only evaluating those elements of the sequence that are effectively requested. Now, if evaluation causes side effects, then these effects could happen several times, should the same lazy sequence be evaluated more than once - and that is probably not what you would ever want to happen.

Zoran Horvat
  • 9,447
  • 3
  • 26
  • 39
  • Can you please elaborate more on why it's a bad idea to cause side-effects in LINQ expressions? I get the idea, but i'm interested in finding out as what issues someone can into if you cause side-effects in LINQ expressions. – Kerim Emurla Feb 25 '18 at 16:33
  • 1
    @KerimEmurla Added more explanation. – Zoran Horvat Feb 25 '18 at 16:34
5

It's deferred execution.

Only if you'll actually enumerate the result you'll execute the statement.

For example:

IEnumerable<List<int>> F() {
    return File.ReadLines("input.txt")
        .Select(a => a.Split(' ').Skip(1).Select(int.Parse).ToList())
        .Where(a => a.Count >= 2)
        .Take(3).OrderBy(a => a.Sum())
        .Select(a => { Console.Write(a[0]); return a; });
}

void Main()
{
    foreach(var r in F()) //the result is enumerated and will execute the select
    {
         //do stuff
    }
}

See other questions:

Deferred execution in C#

MSDN example

What are the benefits of a Deferred Execution in LINQ?

The same thing would happen if you would call F().ToList().

This behavior is especially useful if the enumeration itself requires a lot of resources. Sometimes an underlying framework is able to optimize the enumeration in a later stage.

For example, a smart interperter or expression builder will be able to optimize things if you would call something like:

F().Where(c => ....) 
Stefan
  • 14,240
  • 9
  • 51
  • 69