Como Aceder ao Índice em Loops 'Foreach' em Python
Muitas vezes quando você está fazendo looping sobre uma coleção de itens em Python, você também precisa ter um número ordinal associado a cada item.
Tal número é normalmente referido como o index
.
A forma pítonica de acessar o índice enquanto faz um loop foreach
é utilizar a função embutida enumerate()
.
A função enumerate()
adiciona um índice a cada item de uma coleção iterável.
Você então pode utilizar a função list()
builtin para obter de volta uma lista de tuples.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names))
[(0, 'Bob'), (1, 'Alice'), (2, 'John'), (3, 'Cindy')]
Nota, a indexação Python começa a partir de 0
.
Entretanto, se você quiser começar a indexar a partir de 1
(por exemplo, ao imprimir um relatório de dados), isso é trivialmente alcançado passando um argumento adicional de start
para enumerate
.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names), start=1)
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]
A abordagem acima também é útil se você estiver imprimindo dados de diferentes fontes de dados, mas quiser ter um índice consistente em todos os itens de dados.
>>> 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')]
Note que você não precisa converter um objeto Enumerate
para uma lista.
Ele é um iterável em si, portanto pode iterar sobre ele diretamente.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> for idx, name in enumerate(names):
... print(name)
...
Bob
Alice
John
Cindy
Pode haver outras formas de obter o índice enquanto se faz a iteração sobre uma coleção de itens,
mas utilizar enumerate()
é considerado canônico e é preferível.
Outra opção seria utilizar uma variável de índice separada, inicializá-la manualmente e
aumentá-la manualmente a cada iteração.
Tal abordagem, no entanto, seria considerada uma reinvenção da roda e franzida.
Aqui está uma citação de PEP 279 na qual enumerate()
a função foi introduzida.
Esta PEP introduz uma nova função embutida, enumerate() para simplificar um idioma de looping comumente utilizado. Ele fornece todas as coleções iteráveis com a mesma vantagem que iteritems() oferece aos dicionários – ** uma notação de índice compacta, legível e confiável**.
Você pode perguntar se há implicações de performance ao utilizar enumerate
em seu código.
Bem, você é livre para fazer todas as medidas, mas, por favor, tenha em mente que enumerate
é uma maneira idiomática de acessar um índice de um iterável em um loop ‘para cada’.
O código idiomático é recomendado pelos mantenedores do Python e eles vão fazer tudo para
fazê-la funcionar eficientemente.
E para aqueles de vocês, que estão mais curiosos abaixo é uma possível implementação da função enumerate()
a partir do PEP acima.
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