1087

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.

0

28 Answers 28

1772

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.

24
  • 189
    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”). Commented Feb 9, 2009 at 19:10
  • 12
    @Greg Hewgill No, it's an iterator over the original, no copy is created!
    – André
    Commented Feb 9, 2009 at 19:14
  • 130
    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
    Commented Feb 9, 2009 at 19:27
  • 161
    in this answer though, list(enumerate(a)) DOES create a copy. Commented Feb 9, 2009 at 19:29
  • 71
    @ JF, reversed() doesn't make a copy, but list(enumerate()) DOES make a copy. Commented Feb 9, 2009 at 19:55
260

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

4
  • 41
    [::-1] creates a shallow copy, therefore it doesn't change the array neither "permanently" nor "temporary".
    – jfs
    Commented Feb 9, 2009 at 19:15
  • 6
    This is slightly slower than using reversed, at least under Python 2.7 (tested).
    – kgriffs
    Commented Jan 2, 2014 at 16:49
  • 26
    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
    Commented May 16, 2016 at 15:21
  • 2
    I tested this as well (python 2.7) and it was ~10% slower to use [::-1] vs reversed() Commented Jul 25, 2017 at 22:10
133

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)

8
  • 2
    For versions of Python prior to 3.0, I believe xrange is preferable to range for large len(collection). Commented Feb 9, 2009 at 23:26
  • 18
    This just looks too weird with so many -1's. I would just say reversed(xrange(len(collection)))
    – musiphil
    Commented Sep 7, 2013 at 1: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. Commented Sep 21, 2021 at 17:18
  • 1
    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 ! Commented Feb 8, 2023 at 5:55
  • 1
    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
    Commented May 6, 2023 at 18:36
80

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
9
  • 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
    Commented Feb 9, 2009 at 20:58
  • 1
    reversed(xrange(len(L))) produces the same indices as xrange(len(L)-1, -1, -1).
    – jfs
    Commented Feb 10, 2009 at 16:52
  • 3
    I prefer fewer moving parts to understand: for index, item in enumerate(reversed(L)): print len(L)-1-index, item
    – Don Kirkby
    Commented Nov 5, 2014 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
    Commented Jul 21, 2015 at 18:57
  • 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
    Commented Sep 24, 2015 at 1:01
50

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

2
  • 8
    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. Commented Apr 8, 2021 at 22:12
  • 1
    Worked perfectly for my requirements. Thank you! Commented Feb 16, 2022 at 10:13
42

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.

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

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)
2
  • 1
    this makes me cry
    – CervEd
    Commented May 6, 2021 at 10:27
  • 1
    @CervEd You're absolutely right, it made me cry too when I came back.🙈😅 Updated my answer. -- although range makes me still cry a bit... Commented May 8, 2021 at 14:34
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
>>>
13
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

OR

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

I like the one-liner generator approach:

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

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

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

1
  • 1
    For large lists, that's a waste of CPU time. Use reversed instead. Commented Nov 8, 2020 at 10:13
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]
1
  • 2
    You can also do print a[-(x+1)] and avoid reassigning the index in the body of the loop.
    – Malcolm
    Commented Nov 26, 2017 at 3:22
6
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)
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)
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.

1
  • What version of Python is this? Because range still does the job of xrange in 3.6
    – mrKindo
    Commented Sep 11, 2020 at 16:12
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
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]
3

the reverse function comes in handy here:

myArray = [1,2,3,4]
myArray.reverse()
for x in myArray:
    print x
1
  • 1
    list.reverse() has no return value Commented Feb 9, 2009 at 19:09
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
2

You can also use a while loop:

i = len(collection)-1
while i>=0:
    value = collection[i]
    index = i
    i-=1
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
2

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

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 ) ]
1
  • 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
    Commented Jun 21, 2017 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

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.