1115

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

1820

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.

Sign up to request clarification or add additional context in comments.

24 Comments

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”).
@Greg Hewgill No, it's an iterator over the original, no copy is created!
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].
in this answer though, list(enumerate(a)) DOES create a copy.
@ JF, reversed() doesn't make a copy, but list(enumerate()) DOES make a copy.
|
266

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 Comments

[::-1] creates a shallow copy, therefore it doesn't change the array neither "permanently" nor "temporary".
This is slightly slower than using reversed, at least under Python 2.7 (tested).
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).
I tested this as well (python 2.7) and it was ~10% slower to use [::-1] vs reversed()
141

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 Comments

For versions of Python prior to 3.0, I believe xrange is preferable to range for large len(collection).
This just looks too weird with so many -1's. I would just say reversed(xrange(len(collection)))
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.
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 !
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.
|
81

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 Comments

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.
reversed(xrange(len(L))) produces the same indices as xrange(len(L)-1, -1, -1).
I prefer fewer moving parts to understand: for index, item in enumerate(reversed(L)): print len(L)-1-index, item
@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.
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.
|
51

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

1 Comment

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

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.

Comments

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

3 Comments

The code in your first block there doesn't produce the right output; the output is actually 3 foo\n2 bar\n1 baz
To avoid using "a[i-1]" in first example, use this range "range(len(a)-1, -1, -1)". This is more simplified.
@amiller27 yours is even more wrong... running this in python 3.10 i get 2 baz 1 bar 0 foo
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 Comments

this makes me cry
@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...
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
>>>

Comments

13
>>> l = ["a","b","c","d"]
>>> l.reverse()
>>> l
['d', 'c', 'b', 'a']

OR

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

Comments

11

I like the one-liner generator approach:

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

Comments

7

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

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

1 Comment

For large lists, that's a waste of CPU time. Use reversed instead.
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 Comment

You can also do print a[-(x+1)] and avoid reassigning the index in the body of the loop.
6
def reverse(spam):
    k = []
    for i in spam:
        k.insert(0,i)
    return "".join(k)

Comments

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)

Comments

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 Comment

What version of Python is this? Because range still does the job of xrange in 3.6
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

Comments

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]

Comments

3

the reverse function comes in handy here:

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

1 Comment

list.reverse() has no return value
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

Comments

2

You can also use a while loop:

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

Comments

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

Comments

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

Comments

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 Comment

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

Comments

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

Comments

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

Comments

-1

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.