1036

How do I traverse a list in reverse order in Python? So I can start from collection[len(collection)-1] and end in collection[0].

I also want to be able to access the loop index.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Joan Venge
  • 315,713
  • 212
  • 479
  • 689

28 Answers28

1691

Use the built-in reversed() function:

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

To also access the original index, use enumerate() on your list before passing it to reversed():

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

Since enumerate() returns a generator and generators can't be reversed, you need to convert it to a list first.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 1
    Thanks. Out of curiosity, does this reversed method, creates a separate copy of the collection or just alters the looping? – Joan Venge Feb 09 '09 at 19:09
  • 182
    No copy is created, the elements are reversed on the fly while traversing! This is an important feature of all these iteration functions (which all end on “ed”). – Konrad Rudolph Feb 09 '09 at 19:10
  • The reversed() function makes a copy of the collection. To modify an existing list, use the .reverse() method. – Greg Hewgill Feb 09 '09 at 19:11
  • 11
    @Greg Hewgill No, it's an iterator over the original, no copy is created! – André Feb 09 '09 at 19:14
  • @André: you're right of course, but I was using the same words as the question asked by Joan, so that the answer would be more easily understood. Conceptually, it creates a copy. In implementation, it uses an iterator. – Greg Hewgill Feb 09 '09 at 19:16
  • 2
    @Greg: Your new chunk of code to access the original index creates a second copy of the original collection. It would be better just to do something like i = len(a) - 1 - ridx – Theran Feb 09 '09 at 19:23
  • 2
    Kinda sucks that this has to traverse the entire list before iteration... Still upvoted. – Kenan Banks Feb 09 '09 at 19:23
  • 127
    To avoid the confusion: `reversed()` doesn't modify the list. `reversed()` doesn't make a copy of the list (otherwise it would require O(N) additional memory). If you need to modify the list use `alist.reverse()`; if you need a copy of the list in reversed order use `alist[::-1]`. – jfs Feb 09 '09 at 19:27
  • 148
    in this answer though, list(enumerate(a)) DOES create a copy. – Kenan Banks Feb 09 '09 at 19:29
  • It doesn't quite make a copy, it seems to do the same logic as manually walking backwards. If you call reversed, then alter the list, then iterate over the reversed list, the changes will be reflected by reversed(). – Richard Levasseur Feb 09 '09 at 19:30
  • 5
    It absolutely makes a copy of the list. More accurately a zip of the list with it's positional indexes. – Kenan Banks Feb 09 '09 at 19:33
  • 1
    @Triptych: `reversed([a,b,c])` does *not* create a copy of `[a, b, c]`. – jfs Feb 09 '09 at 19:39
  • 4
    I think there is some confusion here about exactly which example we're discussing. The first example only uses reversed(); the second example uses reversed(list(enumerate())). Clearly the second example makes more copies than the first. I think you're all correct on some level. :) – Greg Hewgill Feb 09 '09 at 19:47
  • 63
    @ JF, reversed() doesn't make a copy, but list(enumerate()) DOES make a copy. – Kenan Banks Feb 09 '09 at 19:55
  • 1
    Thanks for the input guys, but seems like there is confusion about how these methods are implemented. By copy I meant, a deep copy, not an iterator. Iterators are fine but deep copies would slow my code considerable, for several millions of data. – Joan Venge Feb 09 '09 at 20:46
  • 1
    @Joan, you shouldn't be concerned with 'deep' versus 'shallow' copies. That only matters when you're dealing with nested lists. Even a 'shallow' copy will be expensive - it will duplicate the entire list. I believe my answer is the only one that matches your specs AND uses no extra memory. – Kenan Banks Feb 09 '09 at 21:30
  • Thanks Triptych, that's what I mean, not collection copy but an iterator copy. – Joan Venge Feb 09 '09 at 23:47
  • 1
    Although `reversed(list(enumerate(a)))` works it's not optimized. An alternative is proposed here using a lambda function: http://christophe-simonis-at-tiny.blogspot.ca/2008/08/python-reverse-enumerate.html – Bill Jan 24 '16 at 22:11
  • 5
    @Bill I think `enumerate(reversed(a))` would be also a solution. However, indices will be in reversed order i.e. the last element has index `0` – Snow bunting Jul 06 '17 at 15:58
  • @Snowbunting, the indeces can be produces in reversed easily using `len(a)-i-1`, and if accessing a list `b` of the same length, `b[-i-1]` is equivalent to `b[len(a)-i-1]` – CervEd Jun 03 '19 at 09:30
  • In fact, you can use the following generator `(-(ri+1), val) for ri, val in enumerate(reversed(foo))`, see my answer for example – CervEd Jun 03 '19 at 09:55
  • I'd actually prefer @disooqi / Francsics version (`for i in range(len(a)-1, -1, -1)`) since this is one line and realy avoids any list-copying or list creation. – Markus Jun 04 '19 at 11:53
  • in most cases when you want to interate a list in reverse it's because elements might get deleted in the loop, this code doesn't solve that problem – Martijn Scheffer Feb 08 '23 at 05:52
  • No need for using a list(), you can use `enumerate(reversed(a))`, enumerate can handle generators – 27px May 10 '23 at 05:56
250

You can do:

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

(Or whatever you want to do in the for loop.)

The [::-1] slice reverses the list in the for loop (but won't actually modify your list "permanently").

mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 38
    `[::-1]` creates a shallow copy, therefore it doesn't change the array neither "permanently" nor "temporary". – jfs Feb 09 '09 at 19:15
  • 6
    This is slightly slower than using reversed, at least under Python 2.7 (tested). – kgriffs Jan 02 '14 at 16:49
  • 22
    **How this answer works**: it creates a sliced copy of the list with the parameters: *start point*: unspecified (becomes length of list so starts at end), *end point*: unspecified (becomes some magic number other than `0`, probably `-1`, so ends at start) and *step*: `-1` (iterates backwards through list, `1` item at a time). – Edward May 16 '16 at 15:21
  • 2
    I tested this as well (python 2.7) and it was ~10% slower to use [::-1] vs `reversed()` – RustyShackleford Jul 25 '17 at 22:10
121

It can be done like this:

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

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

So your guess was pretty close :) A little awkward but it's basically saying: start with 1 less than len(collection), keep going until you get to just before -1, by steps of -1.

Fyi, the help function is very useful as it lets you view the docs for something from the Python console, eg:

help(range)

Rotkiv
  • 1,051
  • 2
  • 13
  • 33
Alan Rowarth
  • 2,250
  • 2
  • 14
  • 10
  • 1
    For versions of Python prior to 3.0, I believe xrange is preferable to range for large len(collection). – Brian M. Hunt Feb 09 '09 at 23:26
  • I believe you are correct :) iirc, range() generates the whole range as an array but xrange() returns an iterator that only generates the values as they are needed. – Alan Rowarth Feb 09 '09 at 23:57
  • 18
    This just looks too weird with so many `-1`'s. I would just say `reversed(xrange(len(collection)))` – musiphil Sep 07 '13 at 01:18
  • 1
    Thank you for the explanation of the argument values, I also like Barney Szabolcs solution which is based on the same backwards range iterator. Your explanation makes it easy to understand. – Alex Stoneham Sep 21 '21 at 17:18
  • why the second -1 param? and not just 0? – fayssal el ansari May 19 '22 at 07:35
  • @fayssalelansari you are exclusive on the upper bound with `range` – Coder May 23 '22 at 17:15
  • best answer for me, because it actually goes thru the list in reverse order, instead or somehow reversing the list wich won't do what the intended goal is of iterating a list in reverse ! – Martijn Scheffer Feb 08 '23 at 05:55
  • `for i in range(start, end, width ) :` NOTE: while `start` is inclusive the `end` is not included . So for example, if `width=-1`(for reverse iteration) , and `start=len(collection)-1` then `end=-1` helps to iterate till the first element(index=0) of the collection. `end=0` will help iterate reversely upto index 1 of the collection (as index 0 should be excluded. – KNU May 06 '23 at 18:36
79

If you need the loop index, and don't want to traverse the entire list twice, or use extra memory, I'd write a generator.

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
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
  • 3
    I would call the function enumerate_reversed, but that might be only my taste. I believe your answer is the cleanest for the specific question. – tzot Feb 09 '09 at 20:58
  • 1
    `reversed(xrange(len(L)))` produces the same indices as `xrange(len(L)-1, -1, -1)`. – jfs Feb 10 '09 at 16:52
  • @JF - yeah at the time I thought I had some reason for not doing it that way, but now I can't remember. Changing it now. – Kenan Banks Feb 10 '09 at 17:22
  • This, but as a one-liner generator: ((i, sequence[i]) for i in reversed(xrange(len(sequence)))) – lkraider Aug 17 '14 at 18:47
  • 3
    I prefer fewer moving parts to understand: `for index, item in enumerate(reversed(L)): print len(L)-1-index, item` – Don Kirkby Nov 05 '14 at 21:56
  • 2
    @Triptych I just had to cope with fact that enumerate from reversed() won't yield reversed indexes, and your code helped a lot. This method should be in the standard library. – oski86 Jul 21 '15 at 18:57
  • reversed() is not needed in this case. `xrange(len(L)-1, -1, -1)` should do the job. By the way, how come `reversed(xrange())` works but `reversed(enumerate())` doesn't? – Antoine Pinsard Aug 26 '15 at 17:32
  • 2
    reversed(xrange()) works because an xrange object has the \_\_reversed\_\_ method as well as the \_\_len\_\_ and \_\_getitem\_\_ methods, and reversed can detect that and use them. But an enumerate object doesn't have \_\_reversed\_\_, \_\_len\_\_ or \_\_getitem\_\_. But *why* doesn't enumerate have them? I don't know that. – FutureNerd Sep 24 '15 at 01:01
  • @FutureNerd because `enumerate` is a pure iterator object where as xrange is technically a sequece. `iter(xrange(..))` however suffers the same restrictions that `enumerate` and any other iterator have. – Tadhg McDonald-Jensen May 14 '16 at 03:26
42

An approach with no imports:

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

Time complexity O(n) and space complexity O(1).

An approach that creates a new list in memory, be careful with large lists:

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

Time complexity O(n) and space complexity O(n).

srgbnd
  • 5,404
  • 9
  • 44
  • 80
Kenan
  • 13,156
  • 8
  • 43
  • 50
  • 7
    This answer should be the top one, the first approach leaves the list intact, no copies are made and we are simply walking the indices backwards. Very fast. The second approach will create a new list so be aware. – Amro Younes Apr 08 '21 at 22:12
  • 1
    Worked perfectly for my requirements. Thank you! – Johnny John Boy Feb 16 '22 at 10:13
41

The reversed builtin function is handy:

for item in reversed(sequence):

The documentation for reversed explains its limitations.

For the cases where I have to walk a sequence in reverse along with the index (e.g. for in-place modifications changing the sequence length), I have this function defined an my codeutil module:

from six.moves import zip as izip, range as xrange

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

This one avoids creating a copy of the sequence. Obviously, the reversed limitations still apply.

tzot
  • 92,761
  • 29
  • 141
  • 204
16

Also, you could use either "range" or "count" functions. As follows:

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

3 baz
2 bar
1 foo

You could also use "count" from itertools as following:

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
  • 617
  • 10
  • 19
  • The code in your first block there doesn't produce the right output; the output is actually `3 foo\n2 bar\n1 baz` – amiller27 Jun 22 '18 at 05:49
  • To avoid using "a[i-1]" in first example, use this range "range(len(a)-1, -1, -1)". This is more simplified. – Francisc Dec 23 '18 at 22:48
14

In python 3, list creates a copy, so reversed(list(enumerate(collection)) could be inefficient, generating yet an other list is not optimized away.

If collection is a list for sure, then it may be best to hide the complexity behind an iterator

def reversed_enumerate(collection: list):
    for i in range(len(collection)-1, -1, -1):
        yield i, collection[i]

so, the cleanest is:

for i, elem in reversed_enumerate(['foo', 'bar', 'baz']):
    print(i, elem)
Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
13

How about without recreating a new list, you can do by indexing:

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

OR

>>> length = len(foo)
>>> for i in range(length):
...     print foo[length-i-1]
...
4d
3c
2b
1a
>>>
James Sapam
  • 16,036
  • 12
  • 50
  • 73
13
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

OR

>>> print l[::-1]
['d', 'c', 'b', 'a']
Freddy
  • 2,216
  • 3
  • 31
  • 34
11

I like the one-liner generator approach:

((i, sequence[i]) for i in reversed(xrange(len(sequence))))
lkraider
  • 4,111
  • 3
  • 28
  • 31
7

for what ever it's worth you can do it like this too. very simple.

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

Use list.reverse() and then iterate as you normally would.

http://docs.python.org/tutorial/datastructures.html

bluish
  • 26,356
  • 27
  • 122
  • 180
Bill Konrad
  • 357
  • 2
  • 4
6
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)
dreamcrash
  • 47,137
  • 25
  • 94
  • 117
Jase
  • 61
  • 2
  • 4
5

If you need the index and your list is small, the most readable way is to do reversed(list(enumerate(your_list))) like the accepted answer says. But this creates a copy of your list, so if your list is taking up a large portion of your memory you'll have to subtract the index returned by enumerate(reversed()) from len()-1.

If you just need to do it once:

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

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

    do_something(index, value)

or if you need to do this multiple times you should use a generator:

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 Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
5

Assuming task is to find last element that satisfies some condition in a list (i.e. first when looking backwards), I'm getting following numbers.

Python 2:

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

So, the ugliest option xrange(len(xs)-1,-1,-1) is the fastest.

Python 3 (different machine):

>>> timeit.timeit('for i in range(len(xs)-1,-1,-1):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', number=400000)
4.48873088900001
>>> timeit.timeit('for i in reversed(range(0, len(xs))):\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', number=400000)
4.540959084000008
>>> timeit.timeit('for i, x in enumerate(reversed(xs), 1):\n    if 128 == x: break', setup='xs, n = range(256), 0', number=400000)
1.9069805409999958
>>> timeit.timeit('for i, x in enumerate(xs[::-1]):\n    if 128 == x: break', setup='xs, n = range(256), 0', number=400000)
2.960720073999994
>>> timeit.timeit('for i in range(len(xs), 0, -1):\n    if 128 == xs[i - 1]: break', setup='xs, n = range(256), 0', number=400000)
5.316207007999992
>>> timeit.timeit('i = len(xs)\nwhile 0 < i:\n    i -= 1\n    if 128 == xs[i]: break', setup='xs, n = range(256), 0', number=400000)
5.802550058999998

Here, enumerate(reversed(xs), 1) is the fastest.

wonder.mice
  • 7,227
  • 3
  • 36
  • 39
4

If you don't mind the index being negative, you can do:

>>> a = ["foo", "bar", "baz"]
>>> for i in range(len(a)):
...     print(~i, a[~i]))
-1 baz
-2 bar
-3 foo
jss367
  • 4,759
  • 14
  • 54
  • 76
4

I think the most elegant way is to transform enumerate and reversed using the following generator

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

which generates a the reverse of the enumerate iterator

Example:

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

Result:

[6, 4, 2]
CervEd
  • 3,306
  • 28
  • 25
3

the reverse function comes in handy here:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x
bchhun
  • 18,116
  • 8
  • 28
  • 31
2

To use negative indices: start at -1 and step back by -1 at each iteration.

>>> 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
  • 1,890
  • 1
  • 16
  • 28
2

You can also use a while loop:

i = len(collection)-1
while i>=0:
    value = collection[i]
    index = i
    i-=1
Yuval A.
  • 5,849
  • 11
  • 51
  • 63
2

You can use a negative index in an ordinary for loop:

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

To access the index as though you were iterating forward over a reversed copy of the collection, 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

To access the original, un-reversed index, 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
  • 510
  • 3
  • 5
  • 19
1

The other answers are good, but if you want to do as List comprehension style

collection = ['a','b','c']
[item for item in reversed( collection ) ]
fedmich
  • 5,343
  • 3
  • 37
  • 52
  • 2
    Isn't this just the same as reversed(collection)? Adding the list comprehension does nothing, except unnecessary computation. It is like writing a = [item for item in [1, 2, 3]] vs a = [1, 2, 3]. – EpicDavi Jun 21 '17 at 20:26
1
input_list = ['foo','bar','baz']
for i in range(-1,-len(input_list)-1,-1)
    print(input_list[i])

i think this one is also simple way to do it... read from end and keep decrementing till the length of list, since we never execute the "end" index hence added -1 also

Varun Maurya
  • 337
  • 4
  • 18
1

I'm confused why the obvious choice did not pop up so far:

If reversed() is not working because you have a generator (as the case with enumerate()), just use sorted():

>>> l = list( 'abcdef' )
>>> sorted( enumerate(l), reverse=True )
[(5, 'f'), (4, 'e'), (3, 'd'), (2, 'c'), (1, 'b'), (0, 'a')]
Suuuehgi
  • 4,547
  • 3
  • 27
  • 32
1

As a beginner in python, I found this way more easy to understand and reverses a list.

say numlst = [1, 2, 3, 4]

for i in range(len(numlst)-1,-1,-1):

ie., for i in range(3,-1,-1), where 3 is length of list minus 1,
second -1 means list starts from last element and 
third -1 signifies it will traverse in reverse order.

print( numlst[ i ] )

o/p = 4, 3, 2, 1

EdwardFunnyHands
  • 103
  • 2
  • 11
0

A simple way :

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

for i in reversed(range(0, n)):
    print("%d %d" %(i, arr[i]))
rashedcs
  • 3,588
  • 2
  • 39
  • 40
0

you can use a generator:

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

finally:

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

hope this help you.

Neuron
  • 5,141
  • 5
  • 38
  • 59
AXin
  • 23
  • 1
  • 6