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.

Joan Venge
fuente

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.

Greg Hewgill
fuente
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").

mipadi
fuente
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
Tríptico
fuente
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)

Alan Rowarth
fuente
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.

tzot
fuente
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
>>>
James Sapam
fuente
9
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

O

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

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

((i, sequence[i]) for i in reversed(xrange(len(sequence))))
lkraider
fuente
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
disooqi
fuente
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)
Kenan
fuente
3
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)
Jase
fuente
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]
emorphus
fuente
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()

Barney
fuente
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)
Boris
fuente
1

La función inversa es útil aquí:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x
bchhun
fuente
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
Yuval A.
fuente
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
Malcolm
fuente
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
jss367
fuente
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]
CervEd
fuente
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 ) ]
fedmich
fuente
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
stroz
fuente
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]))
rashedcs
fuente
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

Varun Maurya
fuente
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.

wonder.mice
fuente
-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.

Xin
fuente