c# - Linq + foreach loop optimization -


so found myself writing loop similar one:

        var headers = new dictionary<string, string>();         ...         foreach (var header in headers)         {             if (string.isnullorempty(header.value)) continue;             ...         } 

which works fine, iterates through dictionary once , need do. however, ide suggesting more readable / optimized alternative, disagree:

        var headers = new dictionary<string, string>();         ...         foreach (var header in headers.where(header => !string.isnullorempty(header.value)))         {             ...         } 

but wont iterate through dictionary twice? once evaluate .where(...) , once for-each loop?

if not, , second code example iterates dictionary once, please explain why , how.

the code continue twice fast.

i ran following code in linqpad, , results consistently clause continue twice fast.

void main() {     var headers = enumerable.range(1,1000).todictionary(i => "k"+i,i=> % 2 == 0 ? null : "v"+i);     var stopwatch = new stopwatch();      var sb = new stringbuilder();      stopwatch.start();      foreach (var header in headers.where(header => !string.isnullorempty(header.value)))         sb.append(header);     stopwatch.stop();     console.writeline("using linq : " + stopwatch.elapsedticks);      sb.clear();     stopwatch.reset();      stopwatch.start();     foreach (var header in headers)     {         if (string.isnullorempty(header.value)) continue;         sb.append(header);     }     stopwatch.stop();      console.writeline("using continue : " + stopwatch.elapsedticks);  } 

here of results got

using linq : 1077 using continue : 348  using linq : 939 using continue : 459  using linq : 768 using continue : 382  using linq : 1256 using continue : 457  using linq : 875 using continue : 318 

in general linq going slower when working evaluated ienumerable<t>, foreach counterpart. reason linq-to-objects high-level wrapper of these lower level language features. benefit using linq here not performance, provision of consistent interface. linq absolutely provide performance benefits, come play when working resources not in active memory (and allow leverage ability optimize code executed). when alternative code optimal alternative, linq has go through redundant process call same code have written anyway. illustrate this, i'm going paste code below called when use linq's where operator on loaded enumerable:

public static ienumerable<tsource> where<tsource>(this ienumerable<tsource> source, func<tsource, bool> predicate) {     if (source == null)     {         throw error.argumentnull("source");     }     if (predicate == null)     {         throw error.argumentnull("predicate");     }     if (source iterator<tsource>)     {         return ((iterator<tsource>) source).where(predicate);     }     if (source tsource[])     {         return new wherearrayiterator<tsource>((tsource[]) source, predicate);     }     if (source list<tsource>)     {         return new wherelistiterator<tsource>((list<tsource>) source, predicate);     }     return new whereenumerableiterator<tsource>(source, predicate); } 

and here whereselectenumerableiterator<tsource,tresult> class. predicate field delegate pass where() method. see gets executed in movenext method (as redundant null checks). see enumerable looped through once. stacking where clauses result in creation of multiple iterator classes (wrapping predecessors), not result in multiple enumeration actions (due deferred execution). keep in mind when write lambda this, creating new delegate instance (also affecting performance in minor way).

private class whereselectenumerableiterator<tsource, tresult> : enumerable.iterator<tresult> {     private ienumerator<tsource> enumerator;     private func<tsource, bool> predicate;     private func<tsource, tresult> selector;     private ienumerable<tsource> source;      public whereselectenumerableiterator(ienumerable<tsource> source, func<tsource, bool> predicate, func<tsource, tresult> selector)     {         this.source = source;         this.predicate = predicate;         this.selector = selector;     }      public override enumerable.iterator<tresult> clone()     {         return new enumerable.whereselectenumerableiterator<tsource, tresult>(this.source, this.predicate, this.selector);     }      public override void dispose()     {         if (this.enumerator != null)         {             this.enumerator.dispose();         }         this.enumerator = null;         base.dispose();     }      public override bool movenext()     {         switch (base.state)         {             case 1:                 this.enumerator = this.source.getenumerator();                 base.state = 2;                 break;              case 2:                 break;              default:                 goto label_007c;         }         while (this.enumerator.movenext())         {             tsource current = this.enumerator.current;             if ((this.predicate == null) || this.predicate(current))             {                 base.current = this.selector(current);                 return true;             }         }         this.dispose();     label_007c:         return false;     }      public override ienumerable<tresult2> select<tresult2>(func<tresult, tresult2> selector)     {         return new enumerable.whereselectenumerableiterator<tsource, tresult2>(this.source, this.predicate, enumerable.combineselectors<tsource, tresult, tresult2>(this.selector, selector));     }      public override ienumerable<tresult> where(func<tresult, bool> predicate)     {         return (ienumerable<tresult>) new enumerable.whereenumerableiterator<tresult>(this, predicate);     } } 

i think performance difference justifiable, because linq code easier maintain , reuse. things offset performance issues (like declaring anonymous lambda delegates , expressions static readonly fields in common class). in reference actual question, continue clause faster linq alternative.


Comments

Popular posts from this blog

django - How can I change user group without delete record -

java - Need to add SOAP security token -

java - EclipseLink JPA Object is not a known entity type -