c# - Should IEnumerable returned from OrderBy be evaluated if used multiple times? -


i'm looking @ code calls extension method orderby. resulting ienumerable potentially used multiple times. i've heard linq, better evaluate expressions if may used more once, because if don't linq query executed more once. case here also? (initially, looking @ code, didn't realise linq, see msdn documentation orderby in linq namespace.)

to make concrete, code looks this, except item being enumerated more complicated int , there may many more orders of magnitude more of them there in simple example.

ienumerable<int> multiply(ienumerable<int> list, int howmany, int k) {     return list.take(howmany).select(i => * k); }  void main() {     int[] unsorted = { 1, 7, 3, 9, 4 };     ienumerable<int> sorted = unsorted.orderby(i=>i); // add .tolist() ?     for(int k=1; k<=3; ++k) {         ienumerable<int> multiplied = multiply(sorted, k, k);         console.writeline(string.join(", ", multiplied));     } } 

this code has same output regardless of whether use .tolist() or not.

1 2, 6 3, 9, 12 

it seems surprising code sorting on , on again. if is, , ought have .tolist(), output same, how, in general, should know .tolist() required? seeing magic words

deferred execution

in documentation?


to address @matt burland's suggestion should test performance myself changed program following (using doubles avoid overflow problems).

using system; using system.collections.generic; using system.linq; using system.diagnostics;  namespace orderbyperformancetest {     class program     {         static ienumerable<double> multiply(ienumerable<double> list, int howmany, double k)         {             return list.take(howmany).select(i => * k);         }          static void main(string[] args)         {             int n = 1000;             ienumerable<double> unsorted = enumerable.range(0, n).select(i => (double)(n-i));             //console.writeline(string.join(", ", unsorted));             ienumerable<double> sorted1 = unsorted.orderby(i => i); // add .tolist() ?             //console.writeline(string.join(", ", sorted1));             var sw = new stopwatch();             sw.start();             double sum = 0;             (int k = 1; k <= n; ++k)             {                 ienumerable<double> multiplied = multiply(sorted1, k, k);                 sum += multiplied.sum();                 //console.writeline(string.join(", ", multiplied));             }             sw.stop();             console.writeline("time {0}ms, sum {1}", sw.elapsedmilliseconds, sum);         }     } } 

result:

  • without tolist, 115ms
  • with tolist, 10ms

(sum same in both cases)

when use linq expression, result of expression not calculated @ definition of expression when iterate on it.

if iterate multiple times result calculated (and can different if base list use in linq expression changed).

if use tolist() , keep result of method, result calculated , 1 time, , when iterate multiple times on result of tolist() method sure have same output.


Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

Python ctypes access violation with const pointer arguments -