Assez souvent, j'ai trouvé la nécessité de traiter une liste par paires. Je me demandais quel serait le moyen pythonique et efficace de le faire, et j'ai trouvé ceci sur Google:
pairs = zip(t[::2], t[1::2])
Je pensais que c'était assez pythonique, mais après une discussion récente entre les idiomes et l'efficacité , j'ai décidé de faire quelques tests:
import time
from itertools import islice, izip
def pairs_1(t):
return zip(t[::2], t[1::2])
def pairs_2(t):
return izip(t[::2], t[1::2])
def pairs_3(t):
return izip(islice(t,None,None,2), islice(t,1,None,2))
A = range(10000)
B = xrange(len(A))
def pairs_4(t):
# ignore value of t!
t = B
return izip(islice(t,None,None,2), islice(t,1,None,2))
for f in pairs_1, pairs_2, pairs_3, pairs_4:
# time the pairing
s = time.time()
for i in range(1000):
p = f(A)
t1 = time.time() - s
# time using the pairs
s = time.time()
for i in range(1000):
p = f(A)
for a, b in p:
pass
t2 = time.time() - s
print t1, t2, t2-t1
Voici les résultats sur mon ordinateur:
1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578
Si je les interprète correctement, cela devrait signifier que la mise en œuvre de listes, l'indexation de listes et le découpage de listes en Python sont très efficaces. C'est un résultat à la fois réconfortant et inattendu.
Existe-t-il une autre «meilleure» façon de parcourir une liste par paires?
Notez que si la liste a un nombre impair d'éléments, le dernier ne sera dans aucune des paires.
Quelle serait la bonne façon de s'assurer que tous les éléments sont inclus?
J'ai ajouté ces deux suggestions à partir des réponses aux tests:
def pairwise(t):
it = iter(t)
return izip(it, it)
def chunkwise(t, size=2):
it = iter(t)
return izip(*[it]*size)
Voici les résultats:
0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
Résultats à ce jour
Le plus pythonique et le plus efficace:
pairs = izip(t[::2], t[1::2])
Le plus efficace et le plus pythonique:
pairs = izip(*[iter(t)]*2)
Il m'a fallu un moment pour comprendre que la première réponse utilise deux itérateurs tandis que la seconde en utilise un seul.
Pour traiter des séquences avec un nombre impair d'éléments, la suggestion a été d'augmenter la séquence d'origine en ajoutant un élément ( None
) qui est associé au dernier élément précédent, ce qui peut être réalisé avec itertools.izip_longest()
.
finalement
Notez que, dans Python 3.x, zip()
se comporte comme itertools.izip()
, et itertools.izip()
est parti.