0

I'm looking to break down the reverse() function and write it out in code for practice. I eventually figured out how to do it (step thru the original list backwards and append to the new 'reversed' list) but wondering why this doesn't work.

def reverse(list):
    newlist = []
    index = 0
    while index < len(list):
        newlist[index] = list[(len(list)) - 1 - index]
        index = index + 1
    return newlist

list = [1, 2, 3, 4, 5]
print(reverse(list))
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
SpicyClubSauce
  • 4,076
  • 13
  • 37
  • 62
  • `wondering why this doesn't work` - Please explain the problem clearly. – thefourtheye Apr 13 '15 at 02:52
  • 1
    `list` is a reserved keyword in python - **do not** use it as a variable! – Nir Alfasi Apr 13 '15 at 03:01
  • Note that the built-in [`reverse`](https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types) isn't a function, it's a method of `list`, and it modifies the list in-place, rather than building a new one. If you're thinking of the function [`reversed`](https://docs.python.org/3/library/functions.html#reversed), that's more interesting—but it doesn't build a new list either; it just returns a reverse-iterator over the existing list. – abarnert Apr 13 '15 at 03:02

6 Answers6

5

In Python, you cannot access/update an element of a list, if the index is not in the range of 0 and length of the list - 1.

In your case, you are trying to assign to element at 0, but the list is empty. So, it doesn't have index 0. That is why it fails with the error,

IndexError: list assignment index out of range

Instead, you can use append function, like this

    newlist.append(list[(len(list)) - 1 - index])

Apart from that, you can use range function to count backwards like this

for index in range(len(list) - 1, -1, -1):
    newlist.append(list[index])

you don't even have to increment the index yourself, for loop takes care of it.


As suggested by @abarnert, you can actually iterate the list and add the elements at the beginning every time, like this

>>> def reverse(mylist):
...     result = []
...     for item in mylist:
...         result.insert(0, item)
...     return result
... 
>>> reverse([1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]

If you want to create a new reversed list, you may not have to write a function on your own, instead you can use the slicing notation to create a new reversed list, like this

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]

but this doesn't change the original object.

>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
>>> mylist
[1, 2, 3, 4, 5]

if you want to change the original object, just assign the slice back to the slice of the original object, like this

>>> mylist
[1, 2, 3, 4, 5]
>>> mylist[:] = mylist[::-1]
>>> mylist
[5, 4, 3, 2, 1]

Note: reversed actually returns a reverse iterator object, not a list. So, it doesn't build the entire list reversed. Instead it returns elements one by one when iterated with next protocol.

>>> reversed([1, 2, 3, 4, 5])
<list_reverseiterator object at 0x7fdc118ba978>
>>> for item in reversed([1, 2, 3, 4, 5]):
...     print(item)
...     
... 
5
4
3
2
1

So, you might want to make it a generator function, like this

>>> def reverse(mylist):
...     for index in range(len(mylist) - 1, -1, -1):
...         yield mylist[index]
...     
... 
>>> reverse([1, 2, 3, 4, 5])
<generator object reverse at 0x7fdc118f99d8>

So the reverse function returns a generator object. If you want a list, then you can create one with list function, like this

>>> list(reverse([1, 2, 3, 4, 5]))
[5, 4, 3, 2, 1]

if you are just going to process it one by one, then iterate it with a for loop, like this

>>> for i in reverse([1, 2, 3, 4, 5]):
...     print(i)
...     
... 
5
4
3
2
1
Community
  • 1
  • 1
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • 1
    Some great ideas on how to rethink his code instead of just mechanically fix it. One other suggestion you might want to make is `for value in mylist: newlist.insert(0, value)`, to show how you can often simplify things by turning them around (no need to calculate `len(lst) - index - 1` if you just insert in reverse order instead of iterating in reverse order). – abarnert Apr 13 '15 at 03:15
  • @abarnert Ah, thanks :-) Its a nice suggestion. I edited to include it. Please check :-) – thefourtheye Apr 13 '15 at 03:33
3

First off don't override build-ins (list in your case) second newlist has a len of 0 therefore cannot be accessed by index.

def reverse(mylist):
    newlist = [0] * len(mylist)
    index = 0
    while index < len(mylist):
        newlist[index] = mylist[(len(mylist)) - 1 - index]
        index = index + 1
    return newlist

mylist = [1, 2, 3, 4, 5]
print(reverse(mylist))

you can create a list with values of the same lenght as your input list like so

newlist = [0] * len(mylist)
John
  • 13,197
  • 7
  • 51
  • 101
1

You can't assign to an arbitrary index for a 0-length list. Doing so raises an IndexError. Since you're assigning the elements in order, you can just do an append instead of an assignment to an index:

newlist.append(l[(len(l)) - 1 - index])

Append modifies the list and increases its length automatically.

Another way to get your original code to work would be to change the initialization of newlist so that it has sufficient length to support your index operations:

newlist = [None for _ in range(len(l))]

I would also like to note that it's not a good idea to name things after built-in types and functions. Doing so shadows the functionality of the built-ins.

Shashank
  • 13,713
  • 5
  • 37
  • 63
1

You need to use list.append. newlist[0] is a valid operation, if the list has atleast one element in it, but newlist is empty in this very first iteration. Also, list is not a good name for a variable, as there is a python builtin container with the same name:

def reverse(lst):
    newlist = []
    index = 0
    while index < len(lst):
        newlist.append(lst[(len(list)) - 1 - index])
        index += 1
    return newlist

list = [1, 2, 3, 4, 5]
print(reverse(list))
Saksham Varma
  • 2,122
  • 13
  • 15
1

To write the function you're trying to write, see thefourtheye's answer.

But that isn't how reverse works, or what it does. Instead of creating a new list, it modifies the existing list in-place.

If you think about it, that's pretty easy: just go through half the indices, for each index N, swap the Nth from the left and the Nth from the right.*

So, sticking with your existing framework:

def reverse(lst):
    index = 0
    while index < len(lst)/2:
        lst[index], lst[len(lst) - 1 - index] = lst[len(lst) - 1 - index], lst[index]
        index = index + 1

As a side note, using while loops like this is almost always a bad idea. If you want to loop over a range of numbers, just use for index in range(len(lst)):. Besides reducing three lines of code to one and making it more obvious what you're doing, it removes multiple places where you could make a simple but painful-to-debug mistake.

Also, note that in most cases, in Python, it's easier to use a negative index to mean "from the right edge" than to do the math yourself, and again it will usually remove a possible place you could easily make a painful mistake. But in this particular case, it might not actually be any less error-prone…


* You do have to make sure you think through the edge cases. It doesn't matter whether for odd lists you swap the middle element with itself or not, but just make sure you don't round the wrong way and go one element too far or too short. Which is a great opportunity to learn about how to write good unit tests…

Community
  • 1
  • 1
abarnert
  • 354,177
  • 51
  • 601
  • 671
0

probably check this out:

def reverse(lst):
     newList = []
     countList = len(lst) - 1
     for x in range(countList,-1,-1):

         newList.append(lst[x])
     return newList

def main():
    lst = [9,8,7,6,5,4,2]
    print(reverse(lst))

main()
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
samlexxy
  • 115
  • 1
  • 1
  • 8