¿Cómo se obtiene el índice de la iteración actual de un bucle foreach?

Resuelto Matt Mitchell asked hace 16 años • 37 respuestas

¿Existe alguna construcción de lenguaje poco común que no haya encontrado (como las pocas que aprendí recientemente, algunas en Stack Overflow) en C# para obtener un valor que represente la iteración actual de un bucle foreach?

Por ejemplo, actualmente hago algo como esto dependiendo de las circunstancias:

int i = 0;
foreach (Object o in collection)
{
    // ...
    i++;
}
Matt Mitchell avatar Sep 04 '08 08:09 Matt Mitchell
Aceptado

Ian Mercer publicó una solución similar a esta en el blog de Phil Haack :

foreach (var item in Model.Select((value, i) => new { i, value }))
{
    var value = item.value;
    var index = item.i;
}

Esto le proporciona el elemento ( item.value) y su índice ( item.i) mediante el uso de esta sobrecarga de LINQSelect :

el segundo parámetro de la función [dentro de Seleccionar] representa el índice del elemento fuente.

Está new { i, value }creando un nuevo objeto anónimo .

Las asignaciones de montón se pueden evitar ValueTuplesi usas C# 7.0 o posterior:

foreach (var item in Model.Select((value, i) => ( value, i )))
{
    var value = item.value;
    var index = item.i;
}

También puedes eliminarlo item.mediante el uso de desestructuración automática:

foreach (var (value, i) in Model.Select((value, i) => ( value, i )))
{
    // Access `value` and `i` directly here.
}
bcahill avatar Jul 11 '2012 16:07 bcahill

Es foreachpara iterar sobre colecciones que implementan IEnumerable. Para ello, llama GetEnumeratora la colección, que devolverá un archivo Enumerator.

Este enumerador tiene un método y una propiedad:

  • MoveNext()
  • Current

Currentdevuelve el objeto en el que se encuentra actualmente el enumerador y MoveNextse actualiza Currental siguiente objeto.

El concepto de índice es ajeno al concepto de enumeración y no se puede realizar.

Por eso, la mayoría de las colecciones se pueden recorrer utilizando un indexador y la construcción de bucle for.

Prefiero usar un bucle for en esta situación en comparación con el seguimiento del índice con una variable local.

FlySwat avatar Sep 04 '2008 01:09 FlySwat

Finalmente, C# 7.0 tiene una sintaxis decente para obtener un índice dentro de un foreachbucle (es decir, tuplas):

foreach (var (item, index) in collection.WithIndex())
{
    Debug.WriteLine($"{index}: {item}");
}

Se necesitaría un pequeño método de extensión:

using System.Collections.Generic;

public static class IEnumerableExtensions {
    public static IEnumerable<(T item, int index)> WithIndex<T>(this IEnumerable<T> self)       
       => self.Select((item, index) => (item, index));
}
user1414213562 avatar Oct 12 '2016 11:10 user1414213562