2

I haven't coded in Python for a long time and sometimes I'm quite confused. When I have an array, like eg.: arr = [0, 1, 0, 3, 12] and say:

for i in arr:
    if i == 0:
       arr.remove(i)

it is removing the two zeroes the way I want. But if the array is something like: arr = [0, 0, 1], with the above method, one 0 will remain. So could someone explain me why the behavior is like that? I don't find an explanation for this.

JrmDel
  • 390
  • 1
  • 4
  • 16
m1ghtfr3e
  • 77
  • 9
  • 1
    Does this answer your question? [How to remove items from a list while iterating?](https://stackoverflow.com/questions/1207406/how-to-remove-items-from-a-list-while-iterating) – Błotosmętek Apr 05 '20 at 13:16

3 Answers3

4

Better try this:

arr = [n for n in arr if n != 0]

This uses a list comprehension, it's a lot safer than what you're doing: removing the elements at the same time you're iterating is a bad idea, and you'll experience problems such as elements not being removed.

This is because the list size is reduced and the iterator traversing it will find less elements than it was expecting when the iteration began.

Óscar López
  • 232,561
  • 37
  • 312
  • 386
1

I think I found why your method doesn't work. The problem comes from the way you iterate.

In your example, your function seems to work for arr = [0,1,0,3,12] but not on your second array arr2 = [0,0,2] and returns [0,2]. One interesting thing to investigate then, is the fact that in your second example, you have two consecutive zeros.

Take a look at this code and try to execute it :

for i in arr:
        print('i = '+str(i))
        if(i == 0):
            arr.remove(i)

With your first array, you noticed that your output is the one you expected but that was lucky. As a matter of fact, if you run the code above, you would see that it prints in your console :

> i = 0
> i = 0
> i = 12

So, actually, this means that your remove statement changes the array you iterate on. After a deletion, you skip an element in your array.

This means you should prefer another way, like the ones suggested in comments.

Hope this helps

JrmDel
  • 390
  • 1
  • 4
  • 16
  • Oh yeah, this makes things more clear. But does this also mean,that it's not suggested to edit a list while iterating over it at the same time, not editing in the means to edit in a ways that the "iteration is edited" too? – m1ghtfr3e Apr 06 '20 at 15:06
  • It's indeed not recommended to modify a list while iterating over it. It reminds me of that ConcurrentModificationException error in Java. It is often better to generate a new list/array. This is what happens when you use a list comprehension (see @Óscar-lópez 's answer) for example. – JrmDel Apr 07 '20 at 07:50
0

you can filter out your zeros with the built-in function filter:

arr = list(filter(None, arr))

you have to pay attention if you use filter function with None as first parameter, this will apply bool over your items if you have elements like None, 0 or the empty string '' the result will be the same, False and all these elements will be filtered out, for safety reasons you may use:

arr = list(filter(lambda x: x != 0 , arr))
kederrac
  • 16,819
  • 6
  • 32
  • 55