0

This is a very tricky problem to explain. I was playing around with Python's list methods, particularly the del index object. I wanted to create a simple script that would create a list of integers from 1 to 100, and then a for loop which would delete the odd numbers from the list.

Here is the script I wrote:

def main():
    num = list(range(1,101))
    print(num)
    for i in range(0,101):
        del num[i]
    print(num)
main()

Seems like it would work right? I thought so too, until I ran it.

I am not sure why, but when i was passed to the del num[i] index, the number itself doubled.

When I ran it, I received IndexError: list assignment index out of range.

When I changed the parameters from range(0,101) to range(0,10), I discovered that it deleted all the odd numbers from 1 to 20.

In other words, i in the index is doubling when it shouldn't. Can I get some information about this?

Oleg Silkin
  • 508
  • 1
  • 5
  • 12

5 Answers5

6

The size of the list is reduced when you delete items. After about 50 loop iterations, you have about 50 items in the list, so the nest iteration tries to delete something outside the list.

Here's a simulated run:

>>> a = [1, 2, 3, 4, 5]
>>> a
[1, 2, 3, 4, 5]
>>> del a[0]
>>> a
[2, 3, 4, 5]
>>> del a[1]
>>> a
[2, 4, 5]
>>> del a[2]
>>> a
[2, 4]
>>> del a[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
Filip Haglund
  • 13,919
  • 13
  • 64
  • 113
0

Your iterate through the range from 0 to 101, and delete one item from num on each iteration, so the length of the num is reducing and you finally get an IndexError.

svfat
  • 3,273
  • 1
  • 15
  • 34
0

When you use the del keyword inside of your for loop, it's completely removing the item from the original num list you made. By doing so, the length of your list is getting smaller and smaller with each iteration through the loop.

This also explains why it's only removing the odd numbers, since the indexes are shifting down after each delete, allowing the even numbers to slip through the cracks of your program:

num = range(1, 5)  # num = [1, 2, 3, 4]
del num[0]  # results in num = [2, 3, 4]
del num [1]  # deletes 3, and num now = [2, 4]
etc. for a longer loop

To delete the odd numbers, consider using a conditional to check the %2 == 0 status and the list.remove() method:

num = range(1, 101)
for i in num:
    if i % 2 != 0:
        num.remove(i)
print(num)

Or a list comprehension inside your main() function:

return [x for x in num if x % 2 == 0]
bobbyz
  • 4,946
  • 3
  • 31
  • 42
  • Oh my, you're completely right. I thought the list would store the deleted values somewhere during the index. This completely explained it to me. Thanks dude! – Oleg Silkin Aug 17 '15 at 19:51
  • I mean I did get to the point where I divided it in half and got it to work, but thank you for explaining why it was not working – Oleg Silkin Aug 17 '15 at 19:57
  • No problem, glad it helped :) – bobbyz Aug 24 '15 at 16:54
0

This problem is verymuch similar to mutating a list while iterating over the same list, go through below link which helps you to understand this situation better.

http://gsb-eng.com/why-python-list-mutation-is-not-a-good-idea/

gsb-eng
  • 1,211
  • 1
  • 9
  • 16
0

for the second for loop, you should use half of the total indices, because at the 50th iteration, 50 elements would be removed, so the total index of the list is reduced to 50 , hence at the 51st iteration , it displays an out of range error.