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.

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.


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").


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

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)


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.


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
>>>

9
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

OU

>>> print l[::-1]
['d', 'c', 'b', 'a']

7

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

((i, sequence[i]) for i in reversed(xrange(len(sequence))))

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

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)

3
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)

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]

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()


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)

1

la fonction inverse est utile ici:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x

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

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

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

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]

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 ) ]

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

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]))

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


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.


-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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.