LINQ evaluates clauses from right to left? That's why seems so many articles which explains "Lazy evaluation" using a Take operation in the end? The following example, Code Snippet 2 a lot faster than Code Snippet 1 because it didn't do "ToList"
Code Snippet 1 (Takes about 13000 msec)
var lotsOfNums = Enumerable.Range(0, 10000000).ToList();
Stopwatch sw = new Stopwatch();
sw.Start();
// Get all the even numbers
var a = lotsOfNums.Where(num => num % 2 == 0).ToList();
// Multiply each even number by 100.
var b = a.Select(num => num * 100).ToList();
var c = b.Select(num => new Random(num).NextDouble()).ToList();
// Get the top 10
var d = c.Take(10);
// a, b, c and d have executed on each step.
foreach (var num in d)
{
Console.WriteLine(num);
}
sw.Stop();
Console.WriteLine("Elapsed milliseconds: " + sw.ElapsedMilliseconds);
Code Snippet 2 (3 msec)
sw.Reset();
sw.Start();
var e = lotsOfNums.Where(num => num % 2 == 0).Select(num => num * 100).Select(num => new Random(num).NextDouble()).Take(10);
foreach (var num in e)
{
Console.WriteLine(num);
}
sw.Stop();
Console.WriteLine("Elapsed milliseconds: " + sw.ElapsedMilliseconds);
Console.Read();
However, for Code Snippet 2, I find the relative position of "Take" is not relevant?
To be specific, I changed from: var e = lotsOfNums.Where(num => num % 2 == 0).Select(num => num * 100).Select(num => new Random(num).NextDouble()).Take(10);
To:
var e = lotsOfNums.Take(10).Where(num => num % 2 == 0).Select(num => num * 100).Select(num => new Random(num).NextDouble());
There's no difference in performance?
Also worth noting, if you move the NextDouble to far right, since LINQ evaluates left to right, your result list will be empty and also Select(NextDouble) forces all subsequent clauses in left to loop thru the whole list, it will take much longer time to evaluate.
var e = lotsOfNums.Select(num => new Random(num).NextDouble()).Where(num => num % 2 == 0).Select(num => num * 100).Take(10);