Parcourez une liste dans l'ordre inverse en Python

701

Je peux donc commencer len(collection)et finir collection[0].

Je veux également pouvoir accéder à l'index de boucle.

Joan Venge
la source

Réponses:

1181

Utilisez la reversed()fonction intégrée:

>>> a = ["foo", "bar", "baz"]
>>> for i in reversed(a):
...     print(i)
... 
baz
bar
foo

Pour accéder également à l'index d'origine, utilisez enumerate()sur votre liste avant de le transmettre à reversed():

>>> for i, e in reversed(list(enumerate(a))):
...     print(i, e)
... 
2 baz
1 bar
0 foo

Étant donné que les enumerate()retours d'un générateur et des générateurs ne peuvent pas être inversés, vous devez le convertir en listpremier.

Greg Hewgill
la source
130
Aucune copie n'est créée, les éléments sont inversés à la volée lors de la traversée! C'est une caractéristique importante de toutes ces fonctions d'itération (qui se terminent toutes sur «ed»).
Konrad Rudolph
9
@Greg Hewgill Non, c'est un itérateur par rapport à l'original, aucune copie n'est créée!
André
92
Pour éviter la confusion: reversed()ne modifie pas la liste. reversed()ne fait pas de copie de la liste (sinon il faudrait O (N) de mémoire supplémentaire). Si vous devez modifier la liste, utilisez alist.reverse(); si vous avez besoin d'une copie de la liste dans l'ordre inverse, utilisez alist[::-1].
jfs
91
dans cette réponse cependant, list (énumérer (a)) crée une copie.
Triptyque le
43
@ JF, reverse () ne fait pas de copie, mais list (enumerate ()) FAIT une copie.
Triptyque le
172

Tu peux faire:

for item in my_list[::-1]:
    print item

(Ou tout ce que vous voulez faire dans la boucle for.)

La [::-1]tranche inverse la liste dans la boucle for (mais ne modifiera pas réellement votre liste "définitivement").

mipadi
la source
24
[::-1]crée une copie superficielle, donc il ne change pas le tableau ni "de façon permanente" ni "temporaire".
jfs
6
C'est légèrement plus lent que d'utiliser inversé, au moins sous Python 2.7 (testé).
kgriffs
14
Comment cette réponse fonctionne : elle crée une copie en tranches de la liste avec les paramètres: point de départ : non spécifié (devient la longueur de la liste commence donc à la fin), point final : non spécifié (devient un nombre magique autre que 0, probablement -1, se termine donc au début ) et étape : -1(itère en arrière dans la liste, 1élément à la fois).
Edward
1
J'ai également testé cela (python 2.7) et il était ~ 10% plus lent à utiliser [:: - 1] vsreversed()
RustyShackleford
67

Si vous avez besoin de l'index de boucle et que vous ne voulez pas parcourir deux fois la liste entière ou utiliser de la mémoire supplémentaire, j'écrirais un générateur.

def reverse_enum(L):
   for index in reversed(xrange(len(L))):
      yield index, L[index]

L = ['foo', 'bar', 'bas']
for index, item in reverse_enum(L):
   print index, item
Triptyque
la source
3
J'appellerais la fonction enumerate_reversed, mais ce n'est peut-être que mon goût. Je crois que votre réponse est la plus claire pour la question spécifique.
tzot
1
reversed(xrange(len(L)))produit les mêmes indices que xrange(len(L)-1, -1, -1).
jfs
2
Je préfère moins de pièces mobiles à comprendre:for index, item in enumerate(reversed(L)): print len(L)-1-index, item
Don Kirkby
2
@Triptych J'ai juste dû faire face au fait que l'énumération de reverse () ne produira pas d'index inversés, et votre code a beaucoup aidé. Cette méthode doit se trouver dans la bibliothèque standard.
oski86
2
inverse (xrange ()) fonctionne car un objet xrange a la méthode __reversed__ ainsi que les méthodes __len__ et __getitem__, et inversé peut le détecter et les utiliser. Mais un objet énuméré n'a pas __reversed__, __len__ ou __getitem__. Mais pourquoi ne pas les énumérer? Je ne le sais pas.
FutureNerd
60

Cela peut se faire comme ceci:

pour i dans la plage (len (collection) -1, -1, -1):
    collection d'impression [i]

    # print (collection [i]) pour python 3. +

Donc, votre supposition était assez proche :) Un peu gênant, mais il dit essentiellement: commencez avec 1 de moins len(collection), continuez jusqu'à ce que vous arriviez juste avant -1, par pas de -1.

Pour info, la helpfonction est très utile car elle vous permet de visualiser les documents pour quelque chose à partir de la console Python, par exemple:

help(range)

Alan Rowarth
la source
1
Pour les versions de Python antérieures à 3.0, je crois que xrange est préférable de tendre pour les grands len (collection).
Brian M. Hunt
Je pense que vous avez raison :) iirc, range () génère toute la gamme sous forme de tableau mais xrange () renvoie un itérateur qui génère uniquement les valeurs nécessaires.
Alan Rowarth
11
Cela semble trop bizarre avec tant de personnes -1. Je dirais justereversed(xrange(len(collection)))
musiphil
22

La reversedfonction intégrée est pratique:

for item in reversed(sequence):

La documentation de reverse explique ses limites.

Pour les cas où je dois parcourir une séquence en sens inverse avec l'index (par exemple pour les modifications sur place modifiant la longueur de la séquence), j'ai cette fonction définie un module my codeutil:

import itertools
def reversed_enumerate(sequence):
    return itertools.izip(
        reversed(xrange(len(sequence))),
        reversed(sequence),
    )

Celui-ci évite de créer une copie de la séquence. De toute évidence, les reversedlimitations s'appliquent toujours.

tzot
la source
9

Que diriez-vous sans recréer une nouvelle liste, vous pouvez le faire en indexant:

>>> foo = ['1a','2b','3c','4d']
>>> for i in range(len(foo)):
...     print foo[-(i+1)]
...
4d
3c
2b
1a
>>>

OU

>>> length = len(foo)
>>> for i in range(length):
...     print foo[length-i-1]
...
4d
3c
2b
1a
>>>
James Sapam
la source
9
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

OU

>>> print l[::-1]
['d', 'c', 'b', 'a']
Freddy
la source
7

J'aime l'approche d'un générateur à une ligne:

((i, sequence[i]) for i in reversed(xrange(len(sequence))))
lkraider
la source
7

Vous pouvez également utiliser les fonctions "plage" ou "nombre". Comme suit:

a = ["foo", "bar", "baz"]
for i in range(len(a)-1, -1, -1):
    print(i, a[i])

3 baz
2 bar
1 foo

Vous pouvez également utiliser "count" d'itertools comme suit:

a = ["foo", "bar", "baz"]
from itertools import count, takewhile

def larger_than_0(x):
    return x > 0

for x in takewhile(larger_than_0, count(3, -1)):
    print(x, a[x-1])

3 baz
2 bar
1 foo
disooqi
la source
Le code de votre premier bloc ne produit pas la bonne sortie; la sortie est en fait3 foo\n2 bar\n1 baz
amiller27
Pour éviter d'utiliser "a [i-1]" dans le premier exemple, utilisez cette plage "range (len (a) -1, -1, -1)". C'est plus simplifié.
Francisc
4

Une approche sans importation:

for i in range(1,len(arr)+1):
    print(arr[-i])

ou

for i in arr[::-1]:
    print(i)
Kenan
la source
3
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)
Jase
la source
3

pour ce que ça vaut, vous pouvez le faire comme ça aussi. très simple.

a = [1, 2, 3, 4, 5, 6, 7]
for x in xrange(len(a)):
    x += 1
    print a[-x]
emorphus
la source
1
Vous pouvez également faire print a[-(x+1)]et éviter de réaffecter l'index dans le corps de la boucle.
Malcolm
2

Une manière expressive de réaliser reverse(enumerate(collection))en python 3:

zip(reversed(range(len(collection))), reversed(collection))

en python 2:

izip(reversed(xrange(len(collection))), reversed(collection))

Je ne sais pas pourquoi nous n'avons pas de raccourci pour cela, par exemple:

def reversed_enumerate(collection):
    return zip(reversed(range(len(collection))), reversed(collection))

ou pourquoi nous n'avons pas reversed_range()

Barney
la source
2

Si vous avez besoin de l'index et que votre liste est petite, le moyen le plus lisible est de faire reversed(list(enumerate(your_list)))comme le dit la réponse acceptée. Mais cela crée une copie de votre liste, donc si votre liste prend une grande partie de votre mémoire , vous devez soustraire l'indice retourné par enumerate(reversed())de len()-1.

Si vous avez juste besoin de le faire une fois:

a = ['b', 'd', 'c', 'a']

for index, value in enumerate(reversed(a)):
    index = len(a)-1 - index

    do_something(index, value)

ou si vous devez le faire plusieurs fois, vous devez utiliser un générateur:

def enumerate_reversed(lyst):
    for index, value in enumerate(reversed(lyst)):
        index = len(lyst)-1 - index
        yield index, value

for index, value in enumerate_reversed(a):
    do_something(index, value)
Boris
la source
1

la fonction inverse est utile ici:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x
bchhun
la source
list.reverse () n'a pas de valeur de retour
Georg Schölly
1

Vous pouvez également utiliser une whileboucle:

i = len(collection)-1
while i>=0:
    value = collection[i]
    index = i
    i-=1
Yuval A.
la source
1

Vous pouvez utiliser un indice négatif dans une boucle for ordinaire:

>>> collection = ["ham", "spam", "eggs", "baked beans"]
>>> for i in range(1, len(collection) + 1):
...     print(collection[-i])
... 
baked beans
eggs
spam
ham

Pour accéder à l'index comme si vous faisiez une itération vers l'avant sur une copie inversée de la collection, utilisez i - 1:

>>> for i in range(1, len(collection) + 1):
...     print(i-1, collection[-i])
... 
0 baked beans
1 eggs
2 spam
3 ham

Pour accéder à l'index d'origine non inversé, utilisez len(collection) - i:

>>> for i in range(1, len(collection) + 1):
...     print(len(collection)-i, collection[-i])
... 
3 baked beans
2 eggs
1 spam
0 ham
Malcolm
la source
1

Si cela ne vous dérange pas que l'indice soit négatif, vous pouvez faire:

>>> a = ["foo", "bar", "baz"]
>>> for i in range(len(a)):
...     print(~i, a[~i]))
-1 baz
-2 bar
-3 foo
jss367
la source
1

Je pense que la façon la plus élégante est de transformer enumerateet d' reversedutiliser le générateur suivant

(-(ri+1), val) for ri, val in enumerate(reversed(foo))

ce qui génère l'inverse de l' enumerateitérateur

Exemple:

foo = [1,2,3]
bar = [3,6,9]
[
    bar[i] - val
    for i, val in ((-(ri+1), val) for ri, val in enumerate(reversed(foo)))
]

Résultat:

[6, 4, 2]
CervEd
la source
0

Les autres réponses sont bonnes, mais si vous voulez faire comme style de compréhension de liste

collection = ['a','b','c']
[item for item in reversed( collection ) ]
fedmich
la source
1
N'est-ce pas la même chose que renversé (collection)? L'ajout de la compréhension de la liste ne fait rien, sauf un calcul inutile. C'est comme écrire a = [item pour item dans [1, 2, 3]] vs a = [1, 2, 3].
EpicDavi
0

Pour utiliser des indices négatifs: commencez à -1 et reculez de -1 à chaque itération.

>>> a = ["foo", "bar", "baz"]
>>> for i in range(-1, -1*(len(a)+1), -1):
...     print i, a[i]
... 
-1 baz
-2 bar
-3 foo
stroz
la source
0

Un moyen simple:

n = int(input())
arr = list(map(int, input().split()))

for i in reversed(range(0, n)):
    print("%d %d" %(i, arr[i]))
rashedcs
la source
0
input_list = ['foo','bar','baz']
for i in range(-1,-len(input_list)-1,-1)
    print(input_list[i])

je pense que celui-ci est également un moyen simple de le faire ... lire depuis la fin et continuer à décrémenter jusqu'à la longueur de la liste, car nous n'exécutons jamais l'index "end", donc ajouté -1 également

Varun Maurya
la source
0

En supposant que la tâche consiste à trouver le dernier élément qui remplit une condition dans une liste (c'est-à-dire d'abord en regardant en arrière), j'obtiens les numéros suivants:

>>> min(timeit.repeat('for i in xrange(len(xs)-1,-1,-1):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
4.6937971115112305
>>> min(timeit.repeat('for i in reversed(xrange(0, len(xs))):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
4.809093952178955
>>> min(timeit.repeat('for i, x in enumerate(reversed(xs), 1):\n    if 128 == x: break', setup='xs, n = range(256), 0', repeat=8))
4.931743860244751
>>> min(timeit.repeat('for i, x in enumerate(xs[::-1]):\n    if 128 == x: break', setup='xs, n = range(256), 0', repeat=8))
5.548468112945557
>>> min(timeit.repeat('for i in xrange(len(xs), 0, -1):\n    if 128 == xs[i - 1]: break', setup='xs, n = range(256), 0', repeat=8))
6.286104917526245
>>> min(timeit.repeat('i = len(xs)\nwhile 0 < i:\n    i -= 1\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', repeat=8))
8.384078979492188

Ainsi, l'option xrange(len(xs)-1,-1,-1)la plus laide est la plus rapide.

wonder.mice
la source
-1

vous pouvez utiliser un générateur:

li = [1,2,3,4,5,6]
len_li = len(li)
gen = (len_li-1-i for i in range(len_li))

enfin:

for i in gen:
    print(li[i])

j'espère que cela vous aidera.

Xin
la source