I want to create a foreach
which skips the first item. I've seen elsewhere that the easiest way to do this is to use myCollection.Skip(1)
, but I have a question:
The MSDN documentation on .Skip()
describes that it "Bypasses a specified number of elements in a sequence and then returns the remaining elements." Does this mean that a call to
foreach(object i in myCollection.Skip(1)) { ... }
Would the program have to perform .Skip(1)
every time the foreach
iterates? Or does foreach
(somewhat like a switch
) not require multiple evaluations of the array?
Would it be more efficient to create a dummy var _dummy = myCollection.Skip(1)
and iterate on this instead?
forEach() does not mutate the array on which it is called.
The foreach loop in C# iterates items in a collection, like an array or a list. It proves useful for traversing through each element in the collection and displaying them. The foreach loop is an easier and more readable alternative to for loop.
The forloop is faster than the foreach loop if the array must only be accessed once per iteration.
Foreach performance is approximately 6 times slower than FOR / FOREACH performance. The FOR loop without length caching works 3 times slower on lists, comparing to arrays. The FOR loop with length caching works 2 times slower on lists, comparing to arrays.
I just mocked your code with this
foreach(var v in Enumerable.Range(1,10).Skip(1)) v.Dump();
And here is the IL generated.
IL_0001: nop IL_0002: ldc.i4.1 IL_0003: ldc.i4.s 0A IL_0005: call System.Linq.Enumerable.Range IL_000A: ldc.i4.1 IL_000B: call System.Linq.Enumerable.Skip//Call to Skip IL_0010: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator IL_0015: stloc.1 // CS$5$0000 IL_0016: br.s IL_0026 IL_0018: ldloc.1 // CS$5$0000 IL_0019: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current IL_001E: stloc.0 // v IL_001F: ldloc.0 // v IL_0020: call LINQPad.Extensions.Dump IL_0025: pop IL_0026: ldloc.1 // CS$5$0000 IL_0027: callvirt System.Collections.IEnumerator.MoveNext IL_002C: stloc.2 // CS$4$0001 IL_002D: ldloc.2 // CS$4$0001 IL_002E: brtrue.s IL_0018 IL_0030: leave.s IL_0042 IL_0032: ldloc.1 // CS$5$0000 IL_0033: ldnull IL_0034: ceq IL_0036: stloc.2 // CS$4$0001 IL_0037: ldloc.2 // CS$4$0001 IL_0038: brtrue.s IL_0041 IL_003A: ldloc.1 // CS$5$0000 IL_003B: callvirt System.IDisposable.Dispose IL_0040: nop IL_0041: endfinally
As you can see Skip
is called only once.
Equivalent c# code would look something like this
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();//Get the enumerator try { int m;//This variable is here prior to c#5.0 while(e.MoveNext()) {//int m; is declared here starting from c#5.0 m = (int)(int)e.Current; //Your code here } } finally { if (e != null) ((IDisposable)e).Dispose(); }
Consider the below code, If foreach calls VeryLongRunningMethodThatReturnsEnumerable
at each iteration then that would be nightmare. Huge flaw in the design of the language. Fortunately it doesn't do that.
foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable()) { //Do something with that obj }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With