Cómo acceder al índice en los bucles 'Foreach' en Python

A menudo, cuando se hace un bucle sobre una colección de artículos en Python también es necesario tener un número ordinal asociado a cada artículo. Este número se denomina normalmente index.

La forma Pythonica de acceder al índice mientras se hace un bucle foreach es usar la función incorporada enumerate().

enumerate() añade un índice a cada elemento de una colección iterable. Entonces puede usar la función incorporada list() para obtener una lista de tuplas.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names))
[(0, 'Bob'), (1, 'Alice'), (2, 'John'), (3, 'Cindy')]

Nota, la indexación en Python comienza desde 0.

Sin embargo, si quiere iniciar la indexación desde 1 (por ejemplo, cuando imprime un informe de datos), se consigue trivialmente pasando un argumento adicional start a enumerate.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names), start=1)
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]

El enfoque anterior también es útil si está imprimiendo datos de diferentes fuentes de datos pero quiere tener un índice consistente en todos los elementos de datos.

>>> data_source1 = ['Bob', 'Alice', 'John', 'Cindy']
>>> data_source2 = ['Sarah', 'Jeff', 'Emily', 'Adam']
>>> list(enumerate(data_source1, start=1))
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]
>>> list(enumerate(data_source2, start=len(data_source1) + 1))
[(5, 'Sarah'), (6, 'Jeff'), (7, 'Emily'), (8, 'Adam')]

Tenga en cuenta que no tiene que convertir un objeto enumerate en una lista. Es un iterable en sí mismo, así que puede iterar sobre él directamente.

>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> for idx, name in enumerate(names):
...   print(name)
...
Bob
Alice
John
Cindy

Puede haber otras formas de obtener el índice mientras se itera sobre una colección de ítems, pero el uso de enumerate() se considera canónico y se prefiere.

Otra opción sería usar una variable de índice separada, inicializarla manualmente y incrementarlo manualmente en cada iteración. Sin embargo, tal enfoque se consideraría una reinvención de la rueda y estaría mal visto.

He aquí una cita de PEP 279 en la que se introdujo la función enumerate().

This PEP introduces a new built-in function, enumerate() to simplify a commonly used looping idiom. It provides all iterable collections with the same advantage that iteritems() affords to dictionaries – a compact, readable, reliable index notation.

Puedes preguntar si hay alguna implicación en el rendimiento al usar enumerate en tu código. Bueno, eres libre de hacer todas las mediciones, pero por favor, ten en cuenta que enumerate es una forma idiomática de acceder a un índice de un iterable en un bucle for-each. El código idiomático es recomendado por los mantenedores de Python y ellos harán todo lo posible para hacer que funcione eficientemente.

Y para aquellos de vosotros que tengáis más curiosidad, a continuación se muestra una posible implementación de la función enumerate() del PEP anterior.

def enumerate(collection):
   'Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...'
   i = 0
   it = iter(collection)
   while 1:
       yield (i, it.next())
       i += 1
comments powered by Disqus