No hay nada de malo en usar una variable de contador. De hecho, si se utiliza for
, foreach
while
odo
, una variable de contador debe declararse e incrementarse en algún lugar.
Así que usa este modismo si no estás seguro si tienes una colección indexada adecuadamente:
var i = 0;
foreach (var e in collection) {
// Do stuff with 'e' and 'i'
i++;
}
De lo contrario, use este si sabe que su colección indexable es O (1) para el acceso al índice (que será para Array
y probablemente para List<T>
(la documentación no dice), pero no necesariamente para otros tipos (como 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'
}
Nunca debería ser necesario operarlo 'manualmente' IEnumerator
invocando MoveNext()
e interrogando Current
: le foreach
está ahorrando esa molestia particular ... si necesita omitir elementos, simplemente use uncontinue
en el cuerpo del bucle.
Y solo para completar, dependiendo de lo que estaba haciendo con su índice (las construcciones anteriores ofrecen mucha flexibilidad), puede usar 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));
Usamos lo AsParallel()
anterior, porque ya es 2014, y queremos hacer un buen uso de esos múltiples núcleos para acelerar las cosas. Además, para LINQ 'secuencial', solo obtienes un ForEach()
método de extensión List<T>
yArray
... y no está claro que usarlo sea mejor que hacer un simple foreach
, ya que todavía estás ejecutando un solo subproceso para una sintaxis más fea.
foreach
es proporcionar un mecanismo de iteración común para todas las colecciones, independientemente de si son indexables (List
) o no (Dictionary
).Dictionary
no es indexable, una iteración deDictionary
lo atraviesa en un orden particular (es decir, un enumerador es indexable por el hecho de que produce elementos secuencialmente). En este sentido, podríamos decir que no estamos buscando el índice dentro de la colección, sino más bien el índice del elemento enumerado actual dentro de la enumeración (es decir, si estamos en el primer o quinto o último elemento enumerado).