Come accedere all'indice in loop 'Foreach' in Python
Spesso quando si sta facendo un loop su una collezione di articoli in Python è necessario avere anche un numero ordinale associato ad ogni articolo.
Tale numero è solitamente indicato come indice
.
Il modo pitonico di accedere all’indice mentre si fa un foreach
-loop è quello di usare la funzione integrata enumerate()
.
enumerate()
aggiunge un indice ad ogni elemento di una collezione iterabile.
Si può quindi usare la funzione list()
builtin per ottenere una lista di tuple.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names))
[(0, 'Bob'), (1, 'Alice'), (2, 'John'), (3, 'Cindy')]
Nota, l’indicizzazione Python inizia da 0
.
Tuttavia, se si vuole iniziare l’indicizzazione da 1
(per esempio, quando si stampano i dati di un report), si ottiene banalmente passando un ulteriore argomento start
a enumerate
.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> list(enumerate(names), start=1)
[(1, 'Bob'), (2, 'Alice'), (3, 'John'), (4, 'Cindy')]
L’approccio di cui sopra è utile anche se si stampano dati da diverse fonti di dati ma si vuole avere un indice coerente tra tutti i dati.
>>> 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')]
Si noti che non è necessario convertire un oggetto Enumerate
in una lista.
È esso stesso un iterabile, quindi può iterare direttamente su di esso.
>>> names = ['Bob', 'Alice', 'John', 'Cindy']
>>> for idx, name in enumerate(names):
... print(name)
...
Bob
Alice
John
Cindy
Ci possono essere altri modi per ottenere un indice mentre si itera su un insieme di elementi,
ma l’uso di enumerate()
è considerato canonico ed è preferito.
Un’altra opzione sarebbe quella di usare una variabile indice separata, inizializzarla manualmente e
incrementarlo manualmente ad ogni iterazione.
Un tale approccio, tuttavia, sarebbe considerato una reinvenzione della ruota e disapprovato.
Ecco una citazione da PEP 279 in cui è stata introdotta la funzione enumerate()
.
Questo PEP introduce una nuova funzione incorporata, enumerate() per semplificare un idioma di looping comunemente usato. Fornisce a tutte le raccolte iteritems() lo stesso vantaggio che gli iteritems() offrono ai dizionari – ** una notazione di indice compatta, leggibile, affidabile**.
Ci si può chiedere se ci sono implicazioni di performance nell’uso di enumerate
nel codice.
Bene, siete liberi di fare tutte le misurazioni, ma tenete presente, per favore, che enumerare
è un modo idiomatico per accedere ad un indice di un iterabile in un bucle for-each
.
Il codice idiomatico è raccomandato dai manutentori di Python e faranno tutto per
farla funzionare in modo efficiente.
E per quelli di voi che sono più curiosi di seguito è una possibile implementazione della funzione enumerate()
dal PEP di cui sopra.
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