291

I'm talking about doing something like:

for(i=n; i>=1; --i) {
   //do something with i
}

I can think of some ways to do so in python (creating a list of range(1,n+1) and reverse it, using while and --i, ...) but I wondered if there's a more elegant way to do it. Is there?

EDIT: Some suggested I use xrange() instead of range() since range returns a list while xrange returns an iterator. But in Python 3 (which I happen to use) range() returns an iterator and xrange doesn't exist.

snakile
  • 52,936
  • 62
  • 169
  • 241
  • 3
    a little too late to answer but, I didn't see the easiest solution here so here it is..........................................................`for i in range(n)[::-1]` this will give you `i` in reverse order. Peace out. – Parthik B. Feb 17 '20 at 17:25
  • @ParthikB wouldn't the reverse in the end create extra space? looks like you are creating a new reversed array - i may be wrong? – BigDreamz Sep 13 '20 at 17:07

5 Answers5

444

range() and xrange() take a third parameter that specifies a step. So you can do the following.

range(10, 0, -1)

Which gives

[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 

But for iteration, you should really be using xrange instead. So,

xrange(10, 0, -1)

Note for Python 3 users: There are no separate range and xrange functions in Python 3, there is just range, which follows the design of Python 2's xrange.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
Chinmay Kanchi
  • 62,729
  • 22
  • 87
  • 114
  • 9
    Since this question is about iteration please use xrange instead of range (doesn't matter much for small ranges but starts mattering for large ones). – mzz Aug 13 '10 at 12:51
  • 15
    @mzz -- only in Python 2.x – Katriel Aug 13 '10 at 12:56
  • 4
    I used `range` simply because the OP did. `xrange` vs `range` only matters for _really_ large ranges, like hundreds of megabytes. Also, in Python 3.x, this distinction is gone. – Chinmay Kanchi Aug 13 '10 at 12:57
  • 4
    @Chinmay, why not use your answer as a way of showing best practices to the OP? No reason *not* to suggest using `xrange`. – habnabit Aug 13 '10 at 13:00
  • What is xrange? Is it the same as range but faster? If so then why is it faster? – snakile Aug 13 '10 at 13:31
  • `xrange` produces a _generator_ instead of a `list`. What this means is that instead of taking up all the memory at the start, the value required is produced at the time when it's required. For more details, see http://docs.python.org/tutorial/classes.html#generators – Chinmay Kanchi Aug 13 '10 at 15:53
  • 2
    Turns out xrange doesn't exist in python 3... – snakile Aug 13 '10 at 16:38
  • No, it doesn't. Your question didn't specify which version of python you were using, and the default assumption tends to be python 2.x – Chinmay Kanchi Aug 13 '10 at 17:35
  • 19
    i think you should use range(10, -1, -1) instead of range(10, 0, -1). because range(10, 0, -1) will stop at the index 0, as a result, the index 0 value will not print. – Hatim Nov 30 '15 at 15:03
  • 1
    To Clarify: In Python 3 the Python 2 xrange() function has been renamed as just range() and there is no function which has the same behaviour as the Python 2 range() function. See: [What’s New In Python 3](https://docs.python.org/3/whatsnew/3.0.html#views-and-iterators-instead-of-lists) – mattst Nov 28 '16 at 11:32
  • 7
    Actually you should use range(n-1, -1, -1), this will provide the values between zero and n-1. Both this answer and some of the comments have off-by-one issues. – Chris Flesher Jun 26 '17 at 15:01
  • Yeah in this example you would use (9,-1,-1) – the_raging_deaner Oct 16 '19 at 14:39
  • 1
    @ChrisFlesher you can simply use `range(n)[::-1]` which is translated to `range(n-1, -1, -1)` (tested in python 3.7) – Hassan Dec 02 '19 at 10:48
251
for x in reversed(whatever):
    do_something()

This works on basically everything that has a defined order, including xrange objects and lists.

habnabit
  • 9,906
  • 3
  • 32
  • 26
  • 18
    @Odomontois, no, it doesn't. It returns an iterator. – habnabit Aug 13 '10 at 12:35
  • 1
    Yes. Sorry. It returns result of obj.__reversed__ method. So by default generator objects haven't this like many others iterables. And even reversed(reversed([1,2,3])) raises TypeError. So you HAVE to create a list before send some iterable to reversed in many situations like reversed([expr(i) for i in iterable if cond(i)]) - without brackets it falls. – Odomontois Aug 13 '10 at 15:57
  • 5
    This should be the accepted answer imo – Jamie Nicholl-Shelley Apr 20 '21 at 15:17
  • 1
    The reason this should be accepted is that `reversed(range(3))` produces 2, 1, 0 which is exactly the reverse of `range(3)` while you would have to otherwise do something like `range(3-1, 0-1, -1)` to get the same. It's also more readable than `range(3)[::-1]`. – Dennis Williamson Nov 19 '22 at 19:50
  • This is the best answer, as other comments state, and for instance, try: `for i, val in enumerate(reversed(range(6))): print(i, val)` – NeilG Mar 21 '23 at 08:42
22

All of these three solutions give the same results if the input is a string:

1.

def reverse(text):
    result = ""
    for i in range(len(text),0,-1):
        result += text[i-1]
    return (result)

2.

text[::-1]

3.

"".join(reversed(text))
Laurel
  • 5,965
  • 14
  • 31
  • 57
chocolate codes
  • 339
  • 2
  • 4
12
def reverse(text):
    reversed = ''
    for i in range(len(text)-1, -1, -1):
        reversed += text[i]
    return reversed

print("reverse({}): {}".format("abcd", reverse("abcd")))
Michael Qin
  • 629
  • 6
  • 10
  • This is the best answer. Iterating through the values like with a for loop is not what people want every time. Iterating by index is far more flexible. – Urthor May 01 '22 at 02:40
  • This is by no means the best answer. To iterate in reverse with an index (if that's what you want, and the criteria you are using to say it's better) then use `range` with `reversed` as stated in [this answer](https://stackoverflow.com/a/3476753); it's far simpler. – NeilG Mar 21 '23 at 08:39
2

To reverse a string without using reversed or [::-1], try something like:

def reverse(text):
    # Container for reversed string
    txet=""

    # store the length of the string to be reversed
    # account for indexes starting at 0
    length = len(text)-1

    # loop through the string in reverse and append each character
    # deprecate the length index
    while length>=0:
        txet += "%s"%text[length]
        length-=1
    return txet
  • 2
    Why would you want to do this way? This is rather simple: def reverse(text): new_text = "" for char in text: new_text = char + new_text return new_text – aks Nov 25 '15 at 09:29