There's nothing wrong with using a counter variable. In fact, whether you use for
, foreach
while
or do
, a counter variable must somewhere be declared and incremented.
So use this idiom if you're not sure if you have a suitably-indexed collection:
var i = 0;
foreach (var e in collection) {
// Do stuff with 'e' and 'i'
i++;
}
Else use this one if you know that your indexable collection is O(1) for index access (which it will be for Array
and probably for List<T>
(the documentation doesn't say), but not necessarily for other types (such as LinkedList
)):
// Hope the JIT compiler optimises read of the 'Count' property!
for (var i = 0; i < collection.Count; i++) {
var e = collection[i];
// Do stuff with 'e' and 'i'
}
It should never be necessary to 'manually' operate the IEnumerator
by invoking MoveNext()
and interrogating Current
- foreach
is saving you that particular bother ... if you need to skip items, just use a continue
in the body of the loop.
And just for completeness, depending on what you were doing with your index (the above constructs offer plenty of flexibility), you might use Parallel LINQ:
// First, filter 'e' based on 'i',
// then apply an action to remaining 'e'
collection
.AsParallel()
.Where((e,i) => /* filter with e,i */)
.ForAll(e => { /* use e, but don't modify it */ });
// Using 'e' and 'i', produce a new collection,
// where each element incorporates 'i'
collection
.AsParallel()
.Select((e, i) => new MyWrapper(e, i));
We use AsParallel()
above, because it's 2014 already, and we want to make good use of those multiple cores to speed things up. Further, for 'sequential' LINQ, you only get a ForEach()
extension method on List<T>
and Array
... and it's not clear that using it is any better than doing a simple foreach
, since you are still running single-threaded for uglier syntax.