web-dev-qa-db-fra.com

Le meilleur moyen de créer une liste "inversée" en Python?

En Python, quel est le meilleur moyen de créer une nouvelle liste dont les éléments sont identiques à ceux d’une autre liste, mais dans l’ordre inverse? (Je ne veux pas modifier la liste existante à la place.)

Voici une solution qui m'est venue à l'esprit:

new_list = list(reversed(old_list))

Il est également possible de dupliquer old_list puis inversez le duplicata en place:

new_list = list(old_list) # or `new_list = old_list[:]`
new_list.reverse()

Y a-t-il une meilleure option que j'ai négligée? Sinon, existe-t-il une raison impérieuse (telle que l'efficacité) d'utiliser l'une des approches ci-dessus plutôt que l'autre?

83
davidchambers
newlist = oldlist[::-1]

Le [::-1] slicing (que ma femme Anna aime appeler "le smiley martien" ;-) signifie: découpez toute la séquence en tranches, avec un pas de -1, c’est-à-dire en sens inverse. Cela fonctionne pour toutes les séquences.

Notez que ceci (et les alternatives que vous avez mentionnées) équivaut à une "copie superficielle", c'est-à-dire: si les éléments sont mutables et que vous appelez des mutateurs, les mutations des éléments contenus dans la liste d'origine sont également dans les éléments de la liste inversée, et vice versa. Si vous avez besoin d'éviter cela, un copy.deepcopy (alors que l'opération est toujours potentiellement coûteuse), suivie dans ce cas par un .reverse, est la seule bonne option.

194
Alex Martelli

Maintenant, passons timeit . Indice: Alex's [::-1] est le plus rapide :)

$ p -m timeit "ol = [1, 2, 3]; nl = list(reversed(ol))"
100000 loops, best of 3: 2.34 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = list(ol); nl.reverse();"
1000000 loops, best of 3: 0.686 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = ol[::-1];"
1000000 loops, best of 3: 0.569 usec per loop

$ p -m timeit "ol = [1, 2, 3]; nl = [i for i in reversed(ol)];"
1000000 loops, best of 3: 1.48 usec per loop


$ p -m timeit "ol = [1, 2, 3]*1000; nl = list(reversed(ol))"
10000 loops, best of 3: 44.7 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = list(ol); nl.reverse();"
10000 loops, best of 3: 27.2 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = ol[::-1];"
10000 loops, best of 3: 24.3 usec per loop

$ p -m timeit "ol = [1, 2, 3]*1000; nl = [i for i in reversed(ol)];"
10000 loops, best of 3: 155 usec per loop

Mise à jour: Ajout de la méthode de compilation par liste suggérée par inspectorG4dget. Je laisserai les résultats parler d'eux-mêmes.

53
Sam Dolan

Ajustements

Cela vaut la peine de fournir un point de référence/ajustement de base pour les calculs de timeit effectués par sdolan, qui montrent les performances de 'reverse' sans la conversion souvent inutile list(). Cette opération list() ajoute 26 utilisateurs supplémentaires à l'exécution et n'est nécessaire que dans le cas où un itérateur est inacceptable.

Résultats:

reversed(lst) -- 11.2 usecs

list(reversed(lst)) -- 37.1 usecs

lst[::-1] -- 23.6 usecs

Calculs:

# I ran this set of 100000 and came up with 11.2, twice:
python -m timeit "ol = [1, 2, 3]*1000; nl = reversed(ol)"
100000 loops, best of 3: 11.2 usec per loop

# This shows the overhead of list()
python -m timeit "ol = [1, 2, 3]*1000; nl = list(reversed(ol))"
10000 loops, best of 3: 37.1 usec per loop

# This is the result for reverse via -1 step slices
python -m timeit "ol = [1, 2, 3]*1000;nl = ol[::-1]"
10000 loops, best of 3: 23.6 usec per loop

Conclusions:

La conclusion de ces tests est que reversed() est plus rapide que la tranche [::-1] À 12,4 usecs

7
mekarpeles