Attraversa un elenco in ordine inverso in Python


701

Quindi posso iniziare len(collection)e finire collection[0].

Voglio anche essere in grado di accedere all'indice del ciclo.

Risposte:


1181

Utilizzare la reversed()funzione integrata:

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

Per accedere anche all'indice originale, utilizzare enumerate()l'elenco prima di passarlo a reversed():

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

Poiché enumerate()restituisce un generatore e i generatori non possono essere invertiti, è necessario convertirlo in un listprimo.


130
Non viene creata alcuna copia, gli elementi vengono invertiti al volo durante l'attraversamento! Questa è una caratteristica importante di tutte queste funzioni di iterazione (che terminano tutte in "ed").
Konrad Rudolph,

9
@Greg Hewgill No, è un iteratore sull'originale, non viene creata alcuna copia!
André,

92
Per evitare confusione: reversed()non modifica l'elenco. reversed()non crea una copia dell'elenco (altrimenti richiederebbe O (N) memoria aggiuntiva). Se è necessario modificare l'elenco utilizzare alist.reverse(); se è necessaria una copia dell'elenco in ordine inverso, utilizzare alist[::-1].
jfs,

90
in questa risposta però, list (enumerate (a)) crea una copia.
Trittico

42
@ JF, reversed () non crea una copia, ma list (enumerate ()) FA una copia.
Trittico

172

Tu puoi fare:

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

(O qualunque cosa tu voglia fare nel ciclo for.)

La [::-1]sezione inverte l'elenco nel ciclo for (ma in realtà non modificherà l'elenco in modo "permanente").


24
[::-1]crea una copia superficiale, quindi non cambia l'array né "permanentemente" né "temporaneo".
jfs,

6
Questo è leggermente più lento rispetto all'utilizzo invertito, almeno in Python 2.7 (testato).
kgriffs

14
Come funziona questa risposta : crea una copia suddivisa dell'elenco con i parametri: punto iniziale : non specificato (diventa lunghezza dell'elenco quindi inizia alla fine), punto finale : non specificato (diventa un numero magico diverso da 0, probabilmente -1, quindi termina all'inizio ) e passaggio : -1(scorre indietro nell'elenco, 1elemento alla volta).
Edward,

1
Ho provato anche questo (python 2.7) ed è stato ~ 10% più lento da usare [:: - 1] vsreversed()
RustyShackleford il

67

Se hai bisogno dell'indice di loop e non vuoi attraversare l'intero elenco due volte o utilizzare memoria aggiuntiva, scriverei un generatore.

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
Chiamerei la funzione enumerate_reversed, ma potrebbe essere solo un mio gusto. Credo che la tua risposta sia la più chiara per la domanda specifica.
martedì

1
reversed(xrange(len(L)))produce gli stessi indici di xrange(len(L)-1, -1, -1).
jfs,

2
Preferisco meno parti mobili per capire:for index, item in enumerate(reversed(L)): print len(L)-1-index, item
Don Kirkby,

2
@Triptych Ho appena dovuto far fronte al fatto che l'enumerazione da reverse () non produrrà indici invertiti e il tuo codice ha aiutato molto. Questo metodo dovrebbe essere nella libreria standard.
oski86,

2
reversed (xrange ()) funziona perché un oggetto xrange ha il metodo __reversed__ nonché i metodi __len__ e __getitem__, e reversed può rilevarlo e usarli. Ma un oggetto enumerato non ha __reversed__, __len__ o __getitem__. Ma perché non elencarli? Non lo so.
FutureNerd

60

Si può fare così:

per i nell'intervallo (len (raccolta) -1, -1, -1):
    collezione di stampa [i]

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

Quindi la tua ipotesi era abbastanza vicina :) Un po 'imbarazzante ma in pratica sta dicendo: inizia con 1 in meno di len(collection), continua fino a quando non arrivi a poco prima di -1, con passi di -1.

Cordiali saluti, la helpfunzione è molto utile in quanto consente di visualizzare i documenti per qualcosa dalla console di Python, ad esempio:

help(range)


1
Per le versioni di Python precedenti alla 3.0, credo che xrange sia preferibile per range per len (collezione).
Brian M. Hunt,

Credo che tu abbia ragione :) iirc, range () genera l'intero range come array ma xrange () restituisce un iteratore che genera i valori solo quando sono necessari.
Alan Rowarth,

11
Sembra troppo strano con così tanti -1. Vorrei solo direreversed(xrange(len(collection)))
musiphil,

22

La reversedfunzione integrata è utile:

for item in reversed(sequence):

La documentazione per invertito spiega i suoi limiti.

Per i casi in cui devo percorrere una sequenza al contrario insieme all'indice (ad es. Per modifiche sul posto che cambiano la lunghezza della sequenza), ho questa funzione definita un mio modulo codeutil:

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

Questo evita di creare una copia della sequenza. Ovviamente, le reversedlimitazioni si applicano ancora.


9

Che ne dite senza ricreare un nuovo elenco, puoi farlo indicizzando:

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

Mi piace l'approccio del generatore a una linea:

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

7

Inoltre, è possibile utilizzare le funzioni "intervallo" o "conteggio". Come segue:

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

3 baz
2 bar
1 foo

Puoi anche usare "count" da itertools come segue:

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

Il codice nel tuo primo blocco lì non produce l'output giusto; l'output è in realtà3 foo\n2 bar\n1 baz
amiller27

Per evitare di utilizzare "a [i-1]" nel primo esempio, utilizzare questo intervallo "range (len (a) -1, -1, -1)". Questo è più semplificato.
Francisc,


4

Un approccio senza importazioni:

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

per quanto valga la pena, puoi farlo anche in questo modo. molto semplice.

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

1
Puoi anche fare print a[-(x+1)]ed evitare di riassegnare l'indice nel corpo del loop.
Malcolm,

2

Un modo espressivo per ottenere reverse(enumerate(collection))in Python 3:

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

in Python 2:

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

Non sono sicuro del motivo per cui non abbiamo una scorciatoia per questo, ad es .:

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

o perché non abbiamo reversed_range()


2

Se hai bisogno dell'indice e la tua lista è piccola, il modo più leggibile è fare reversed(list(enumerate(your_list)))come dice la risposta accettata. Ma questo crea una copia della vostra lista, quindi se la vostra lista sta prendendo una grande parte della memoria si dovrà sottrarre l'indice restituito da enumerate(reversed())dalen()-1 .

Se hai solo bisogno di farlo una volta:

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

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

    do_something(index, value)

o se devi farlo più volte dovresti usare un generatore:

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 funzione inversa è utile qui:

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

list.reverse () non ha valore di ritorno
Georg Schölly

1

Puoi anche usare un whileloop:

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

1

Puoi usare un indice negativo in un normale ciclo per:

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

Per accedere all'indice come se stessi ripetendo una copia invertita della raccolta, usa i - 1:

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

Per accedere all'indice originale non invertito, utilizzare 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

Se non ti dispiace che l'indice sia negativo, puoi fare:

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

1

Penso che il modo più elegante sia quello di trasformare enumeratee reversedutilizzare il seguente generatore

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

che genera un contrario enumeratedell'iteratore

Esempio:

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

Risultato:

[6, 4, 2]

0

Le altre risposte sono buone, ma se vuoi fare come stile di comprensione dell'elenco

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

1
Non è esattamente lo stesso di capovolto (collezione)? L'aggiunta della comprensione dell'elenco non fa nulla, tranne il calcolo non necessario. È come scrivere a = [item for item in [1, 2, 3]] vs a = [1, 2, 3].
EpicDavi,

0

Per utilizzare indici negativi: iniziare da -1 e tornare indietro di -1 ad ogni iterazione.

>>> 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 modo semplice:

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

penso che questo sia anche un modo semplice per farlo ... leggi da fine e continua a diminuire fino alla lunghezza della lista, dal momento che non eseguiamo mai l'indice "end" quindi aggiunto -1 anche


0

Supponendo che il compito sia trovare l'ultimo elemento che soddisfi alcune condizioni in un elenco (ovvero prima guardando indietro), sto ottenendo i seguenti numeri:

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

Quindi, l'opzione più brutta xrange(len(xs)-1,-1,-1)è la più veloce.


-1

puoi usare un generatore:

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

spero che questo ti aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.