Conocer el índice del elemento de una iteración dentro de un foreach
Introducción
Recientemente, me encontraba con el método de una clase en C# dentro del cual tenía que recorrer un conjunto de registros bastante grande, y para ello, tenía un bucle foreach.
El proceso dentro del bucle y de tipo batch, pasaba por diferentes estados y circunstancias que desencadenaba un resultado, pero a veces ese proceso no devolvía un resultado correcto.
Si se producía un error o problema, me interesaba registrar en el log los datos clave que me permitieran informar de ello, pero dentro de ese log, y por razones que no vienen ahora al caso, también me interesaba almacenar la posición del índice del elemento dentro del bucle foreach.
Es decir, si estaba procesando «Uno», «Dos», «Tres»… y fallaba en «Dos», dentro de la iteración foreach, el elemento de la colección era el 1 («Uno» => 0, «Dos» => 1, «Tres» => 2,…).
Así que la pregunta sería:
¿Cómo podemos hacer esto?.
Existen muchas posibles soluciones, pero voy a compartir una que es bastante sencilla, pero que no todo el mundo conoce.
Todo lo que mostraré a continuación como posible solución, lo he realizado con LINQ.
Método convencional
Como decía anteriormente, existen diferentes modos o maneras de resolver el problema.
El más característico y simple, es declarar una variable int fuera del bucle, y luego ir sumando una unidad a la variable al final del proceso dentro de cada iteración del bucle foreach.
En todo momento, sabremos qué índice se está tratando dentro de la iteración.
Es un mecanismo sencillo, que funciona.
Sin embargo, existen diferentes formas más directas de llevar a cabo esto mismo sin necesidad de declarar ninguna variable extra adicional que haga las acciones de contador.
Los siguientes ejemplos se basan en el mismo mecanismo, muy similares, pero ligeramente distintas.
Preguntar por el índice dentro del bucle
Dentro del bucle y a través de LINQ, preguntaríamos acerca del elemento actual, para extraer de él el índice y el valor:
foreach (var item in elements) { ... var currentElement = elements.Select((value, index) => (value, index)). Where(s => s.value == item).SingleOrDefault(); Console.WriteLine($"{currentElement.value} in position {currentElement.index}"); }
Iterar sobre un índice, valor directamente
Dentro del bucle foreach, definiremos la pareja de datos índice, valor que vamos a utilizar en la iteración.
De esta manera, cada elemento de la iteración corresponde con un índice, valor sobre el que podemos extraer la información que necesitamos.
foreach (var item in elements.Select((value, index) => (value, index))) { ... Console.WriteLine($"{item.value} in position {item.index}"); }
Iterar sobre índice, valor obteniendo su índice, valor directamente
Parecido al anterior, dentro del bucle foreach declararemos un elemento de tipo índice, valor para cada iteración, pudiendo acceder a sus elementos directamente.
foreach (var (value, index) in elements.Select((value, index) => (value, index))) { ... Console.WriteLine($"{value} in position {index}"); }
Espero que esto te haya resultado útil.
Happy Coding!