Il m'est arrivé assez souvent de devoir traiter une liste par paires. Je me demandais quelle serait la manière pythique 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 impliquant idiomes contre 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 obtenus 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 l'implémentation des listes, de l'indexation des listes et du découpage des listes en Python est très efficace. C'est un résultat à la fois réconfortant et inattendu.
Existe-t-il une autre façon, "meilleure", de parcourir une liste par paires ?
Notez que si la liste comporte un nombre impair d'éléments, le dernier élément ne figurera 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 jusqu'à présent
Très pythoniques et très efficaces :
pairs = izip(t[::2], t[1::2])
Très efficace et très pythique :
pairs = izip(*[iter(t)]*2)
Il m'a fallu un moment pour comprendre que la première réponse utilise deux itérateurs alors que la seconde n'en utilise qu'un seul.
Pour traiter les séquences comportant un nombre impair d'éléments, il a été suggéré d'ajouter un élément à la séquence originale ( None
) qui est apparié avec le dernier élément précédent, ce qui peut être réalisé avec itertools.izip_longest()
.
Enfin
Notez que, dans Python 3.x, zip()
se comporte comme itertools.izip()
et itertools.izip()
est parti.
0 votes
RE : la "bonne façon" -- il n'y a pas de "bonne" façon ! Cela dépend du cas d'utilisation.
0 votes
@Andrew Jaffe J'ai donné les critères du "meilleur" dans ce cas : efficace, et pythonique.
0 votes
@Apalala : Je veux dire que le résultat d'avoir un nombre impair dépend de l'utilisation. Par exemple, vous pouvez simplement omettre le dernier élément, ou ajouter un élément fictif spécifique connu, ou encore dupliquer le dernier élément.
0 votes
@Andrew Jaffe. Le site résultat ne fait pas partie de la question. Le dernier élément ou l'élément impair peut être jumelé ou inclus seul (dans un-tuple ou autre). Ce qui importe, c'est que l'inclusion de l'élément impair ne brise pas la relation efficace ni le pythonique les aspects de la solution (en utilisant
izip_longest()
est une bonne solution). Ce qui viendra plus tard doit savoir qu'il devra traiter un nombre impair de cas si la liste originale avait un nombre impair d'éléments.0 votes
Comment se fait-il que personne (y compris moi) n'ait remarqué que le code pour les timings est incorrect ?
2 votes
@Apalala : parce que vous utilisez un certain charabia au lieu du
timeit
module.0 votes
@SilentGhost En effet, j'ai besoin de m'accrocher à
timeit
.0 votes
Pour ceux qui arrivent en retard, j'ai réparé le charabia auquel @SilentGhost a fait référence.
1 votes
N-duplicated : juste dans une recherche rapide : stackoverflow.com/questions/4501636 , stackoverflow.com/questions/4170295 , stackoverflow.com/questions/434287
0 votes
Lorsque t a un nombre impair d'éléments,
zip(t[::2], t[1::2])
part à la fin.0 votes
Pyderman L'article mentionne
itertools.izip_longest()
.