zjm1126
zjm1126

Reputation: 35672

how to deal with my code error using python

this is my code :

a=[1,0,None,3]

def b(my_list):
    for i in range(len(my_list)):
        if not my_list[i]:
            a.remove(my_list[i])
        else:
            do_something()
    return my_list

a = b(a)
print a

and the error is :

Traceback (most recent call last):
  File "c.py", line 18, in <module>
    a = b(a)
  File "c.py", line 12, in b
    if not my_list[i]:
IndexError: list index out of range

so what can i do ,

thanks

Upvotes: 1

Views: 89

Answers (5)

kevpie
kevpie

Reputation: 26098

A few examples

Important concept is slice assignment my_list[:] = new_list. This provides bulk replacement in a list.

In place update of my_list using slice assignment:

def b(my_list):
    my_list[:] = [ do_something(...) or x for x in my_list if x ]

do_something() should not return anything other than None in this case

Filter then loop:

def b(my_list):
    my_list[:] = filter(None, my_list)
    for x in my_list:
        do_something(...)

Return new list:

def b(my_list):
    new_list = filter(None, my_list)
    for x in new_list:
        do_something(...)
    return new_list

Warning: This could lead to confusion:

def a(my_list):
    ...
    return my_list # same obj as passed in

my_list = a(my_list)

Upvotes: 0

Rumple Stiltskin
Rumple Stiltskin

Reputation: 10405

This will also work:

def b(my_list):
   new_list = filter(lambda x: x, my_list) 
   map(do_something, new_list)
   return new_list

Upvotes: 1

Adam
Adam

Reputation: 17329

There are two problems with your code.

First, unlike C, the range(len(my_list)) expression will only be evaluated at the start. So you'll get 4 iterations of the loop, despite your list getting shorter. That's the cause of your "out of range" error.

Second, when you delete an element from the list the indices of all elements after the deleteted one will decrement. But your loop won't account for that, so in effect the element after the deleted one will be skipped. For example, it looks like your code should remove the 0 and the None. With this structure the None will be missed.

The fix is to use a copy like Greg says, or you can fake a C-style for loop with a counter and a while loop.

Upvotes: 1

Senthil Kumaran
Senthil Kumaran

Reputation: 56851

I get what you are trying to acheive is remove 0 and None (the values that evaluate to False) from your list. First things first, don't operate on the list itself when you are using that list in the loop, instead work on the copy. Also, you can just iterate over the elements instead of say indexing and then accessing it. So the best way to accomplish what you are trying is this.

>>> a=[1,0,None,3]
>>> b = a[:]
>>> for each in a:
...     if not each:
...             b.remove(each)
... 
>>> b
[1, 3]

Upvotes: 3

Greg Hewgill
Greg Hewgill

Reputation: 993105

You are modifying the same list that you're iterating over, inside your loop. You can fix this by making a copy of the list and returning that:

def b(my_list):
    new_list = my_list[:]
    for i in range(len(my_list)):
        if not my_list[i]:
            new_list.remove(my_list[i])
        else:
            do_something()
    return new_list

Normally in Python, when you call a function such as b(a), then inside b, the parameter my_list is a reference to the same list as was passed in (a). The statement new_list = my_list[:] makes a copy of the list that you can modify and return inside the function.

Upvotes: 3

Related Questions