Recorrer una lista en orden inverso en Python


701

Entonces puedo comenzar len(collection)y terminar collection[0].

También quiero poder acceder al índice de bucle.

Respuestas:


1181

Use la reversed()función incorporada:

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

Para acceder también al índice original, úselo enumerate()en su lista antes de pasarlo a reversed():

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

Como enumerate()devuelve un generador y los generadores no se pueden revertir, debe convertirlo en un listprimero.


130
No se crea ninguna copia, los elementos se invierten sobre la marcha mientras se atraviesa. Esta es una característica importante de todas estas funciones de iteración (que terminan en "ed").
Konrad Rudolph

99
@ Greg Hewgill No, es un iterador sobre el original, ¡no se crea ninguna copia!
André

92
Para evitar la confusión: reversed()no modifica la lista. reversed()no hace una copia de la lista (de lo contrario, requeriría O (N) de memoria adicional). Si necesita modificar la lista, use alist.reverse(); si necesita una copia de la lista en orden inverso, use alist[::-1].
jfs

9191
sin embargo, en esta respuesta, list (enumerate (a)) CREA una copia.
Tríptico

43
@ JF, reverse () no hace una copia, pero list (enumerate ()) SÍ hace una copia.
Tríptico

172

Tu puedes hacer:

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

(O lo que quieras hacer en el bucle for.)

El [::-1]segmento invierte la lista en el bucle for (pero en realidad no modificará su lista "permanentemente").


24
[::-1]crea una copia superficial, por lo tanto, no cambia la matriz ni "permanentemente" ni "temporal".
jfs

66
Esto es un poco más lento que el uso inverso, al menos en Python 2.7 (probado).
kgriffs

14
Cómo funciona esta respuesta : crea una copia en rodajas de la lista con los parámetros: punto de inicio : sin especificar (se convierte en la longitud de la lista, por lo que comienza al final), punto de finalización : sin especificar (se convierte en un número mágico distinto de 0, probablemente -1, por lo que termina al principio ) y paso : -1(itera hacia atrás a través de la lista, 1elemento a la vez).
Edward

1
También probé esto (python 2.7) y fue ~ 10% más lento de usar [:: - 1] vsreversed()
RustyShackleford el

67

Si necesita el índice de bucle y no desea recorrer la lista completa dos veces, o usar memoria adicional, escribiría un generador.

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
Llamaría a la función enumerate_reversed, pero eso podría ser solo mi gusto. Creo que su respuesta es la más limpia para la pregunta específica.
tzot

1
reversed(xrange(len(L)))produce los mismos índices que xrange(len(L)-1, -1, -1).
jfs

2
Prefiero entender menos partes móviles:for index, item in enumerate(reversed(L)): print len(L)-1-index, item
Don Kirkby

2
@Triptych Solo tuve que lidiar con el hecho de que enumerar desde reverse () no arrojará índices invertidos, y su código ayudó mucho. Este método debe estar en la biblioteca estándar.
oski86

2
reverse (xrange ()) funciona porque un objeto xrange tiene el método __reversed__ así como los métodos __len__ y __getitem__, y revertido puede detectarlo y usarlo. Pero un objeto enumerado no tiene __ invertido__, __len__ o __getitem__. Pero, ¿por qué no enumerar los tiene? No se eso.
FutureNerd

60

Se puede hacer así:

para i en rango (len (colección) -1, -1, -1):
    colección impresa [i]

    # print (colección [i]) para python 3. +

Entonces su suposición fue bastante cercana :) Un poco incómodo pero básicamente dice: comience con 1 menos que len(collection), continúe hasta llegar justo antes de -1, en pasos de -1.

Para su información, la helpfunción es muy útil ya que le permite ver los documentos de algo de la consola de Python, por ejemplo:

help(range)


1
Para las versiones de Python anteriores a 3.0, creo que xrange es preferible al rango para len grande (colección).
Brian M. Hunt

Creo que tienes razón :) iirc, range () genera todo el rango como una matriz, pero xrange () devuelve un iterador que solo genera los valores cuando son necesarios.
Alan Rowarth

11
Esto se ve muy raro con tantos -1. Solo diríareversed(xrange(len(collection)))
musiphil

22

La reversedfunción integrada es útil:

for item in reversed(sequence):

La documentación para revertir explica sus limitaciones.

Para los casos en los que tengo que caminar una secuencia en reversa junto con el índice (por ejemplo, para modificaciones en el lugar que cambian la longitud de la secuencia), tengo esta función definida en mi módulo codeutil:

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

Éste evita crear una copia de la secuencia. Obviamente, las reversedlimitaciones aún se aplican.


9

¿Qué tal si no recrea una nueva lista, puede hacerlo indexando:

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

O

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

O

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

7

Me gusta el enfoque de generador de una línea:

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

7

Además, puede usar las funciones "rango" o "conteo". Como sigue:

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

3 baz
2 bar
1 foo

También puede usar "contar" de itertools de la siguiente manera:

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

El código en su primer bloque allí no produce la salida correcta; la salida es en realidad3 foo\n2 bar\n1 baz
amiller27

Para evitar el uso de "a [i-1]" en el primer ejemplo, use este rango "rango (len (a) -1, -1, -1)". Esto está más simplificado.
Francisc


4

Un enfoque sin importaciones:

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

o

for i in arr[::-1]:
    print(i)

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

3

por lo que valga la pena, puedes hacerlo así también. muy simple.

a = [1, 2, 3, 4, 5, 6, 7]
for x in xrange(len(a)):
    x += 1
    print a[-x]

1
También puede hacer print a[-(x+1)]y evitar reasignar el índice en el cuerpo del bucle.
Malcolm

2

Una forma expresiva de lograr reverse(enumerate(collection))en Python 3:

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

en python 2:

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

No estoy seguro de por qué no tenemos una abreviatura para esto, por ejemplo:

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

o por qué no tenemos reversed_range()


2

Si necesita el índice y su lista es pequeña, la forma más fácil de leer es hacer lo reversed(list(enumerate(your_list)))que dice la respuesta aceptada. Pero esto crea una copia de su lista, por lo que si su lista está ocupando una gran parte de la memoria que tendrá que restar el índice devuelve enumerate(reversed())a len()-1.

Si solo necesitas hacerlo una vez:

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

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

    do_something(index, value)

o si necesita hacer esto varias veces, debe usar un generador:

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 función inversa es útil aquí:

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

list.reverse () no tiene valor de retorno
Georg Schölly

1

También puedes usar un whilebucle:

i = len(collection)-1
while i>=0:
    value = collection[i]
    index = i
    i-=1

1

Puede usar un índice negativo en un ciclo for ordinario:

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

Para acceder al índice como si estuviera iterando hacia adelante sobre una copia invertida de la colección, use i - 1:

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

Para acceder al índice original no invertido, use 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 no le importa que el índice sea negativo, puede hacer:

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

1

Creo que la forma más elegante es transformar enumeratey reversedusar el siguiente generador

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

que genera un reverso del enumerateiterador

Ejemplo:

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

Resultado:

[6, 4, 2]

0

Las otras respuestas son buenas, pero si quieres hacer una lista de estilo de comprensión

collection = ['a','b','c']
[item for item in reversed( collection ) ]

1
¿No es esto lo mismo que invertido (colección)? Agregar la comprensión de la lista no hace nada, excepto el cálculo innecesario. Es como escribir a = [ítem para ítem en [1, 2, 3]] vs a = [1, 2, 3].
EpicDavi

0

Para usar índices negativos: comience en -1 y retroceda en -1 en cada iteración.

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

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

Creo que esta también es una forma simple de hacerlo ... leer desde el final y seguir decrementando hasta la longitud de la lista, ya que nunca ejecutamos el índice "final", por lo tanto, agregamos -1 también


0

Asumiendo que la tarea es encontrar el último elemento que satisfaga alguna condición en una lista (es decir, primero cuando se mira hacia atrás), obtengo los siguientes números:

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

Entonces, la opción más fea xrange(len(xs)-1,-1,-1)es la más rápida.


-1

puedes usar un generador:

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

finalmente:

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

Espero que esto te ayude.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.