AlphaOmega
AlphaOmega

Reputation: 113

Why does list.remove() not work in this for-loop?

I have a list of lists :

W = [[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]

From each list in W, I want to remove the zero entries.

I have tried the following :

for idx in range(len(W)):
    W[idx].remove(0)
print(W)

But it will always return

[[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]

Nothing has changed here. I am aware of the fact that I cannot change an object while I am iterating over it, however as I am not iterating over W but over len(W), I don't see why my code wouldn't work.

What am I doing wrong?

Upvotes: 1

Views: 837

Answers (7)

Devesh Kumar Singh
Devesh Kumar Singh

Reputation: 20490

A simple list comprehension should be enough.

W = [[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
li  = [ [j] for i in W for j in i if j!=0]
print(li)
#[[5.0], [5.0], [5.0], [5.0]]

Upvotes: 1

kmario23
kmario23

Reputation: 61335

Since there are more than 1 zeros in each sublist, we have to use two for loops, if you want to stick with a loop based solution.

In [75]: for lst in W:
    ...:     num_zeros = lst.count(0)
    ...:     for _ in range(num_zeros):
    ...:         lst.remove(0)


In [76]: W
Out[76]: [[5.0], [5.0], [], [5.0], [5.0]]

Now, your code:

In [79]: for idx in range(len(W)):
    ...:     W[idx].remove(0)
    ...: print(W)

yields the solution:

[[5.0, 0, 0, 0], [5.0, 0, 0], [0, 0], [5.0, 0, 0], [5.0, 0, 0]]

which we can see is short of 1 zeros from the counts of zeros in the input list. This is because remove(obj) will remove only the first occurrence of the object.

Upvotes: 0

Abujmun
Abujmun

Reputation: 21

I would say it's better to use filter with a lambda expression in order to filter out the zero values.

    for idx in range(len(W)):
        W[idx]=list((filter(lambda a: a != 0, W[idx])))
        print(W)

This will give you the next output:

    [[5.0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
    [[5.0], [5.0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
    [[5.0], [5.0], [], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
    [[5.0], [5.0], [], [5.0], [5.0, 0, 0, 0]]
    [[5.0], [5.0], [], [5.0], [5.0]]

Upvotes: 2

mauve
mauve

Reputation: 2763

As avloss said, that remove only removes the first occurrence. Do a list comprehension.

for idx in range(len(W)):
    W[idx] = [i for i in W[idx] if i != 0]
print(W)

and as @meowgoesthedog suggested, you could do an overall list comprehension:

W = [lst[item for item in lst if item !=0] for lst in W]

Upvotes: 6

Arkistarvh Kltzuonstev
Arkistarvh Kltzuonstev

Reputation: 6920

You can use a list comprehension and filter function to delete the items having zero value in every sublist of W :

W = [[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
nw = [list(filter(lambda a: a != 0, k)) for k in W]

OUTPUT :

[[5.0], [5.0], [], [5.0], [5.0]]

Upvotes: 2

avloss
avloss

Reputation: 2636

if you want to remove all 0 elements you can user list comprehension and filter:

W = [[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
for idx in range(len(W)):
    W[idx] = [i for i in W[idx] if i != 0]
print(W)

output looks like this:

[[5.0], [5.0], [], [5.0], [5.0]]

Upvotes: 2

avloss
avloss

Reputation: 2636

This is because l.remove(0) means remove first occurrence of that element. to remove element by index you can use del

W = [[5.0, 0, 0, 0, 0], [5.0, 0, 0, 0], [0, 0, 0], [5.0, 0, 0, 0], [5.0, 0, 0, 0]]
for idx in range(len(W)):
    del W[idx][0]
print(W)

this produces

[[0, 0, 0, 0], [0, 0, 0], [0, 0], [0, 0, 0], [0, 0, 0]]

Upvotes: -2

Related Questions