Not all elements that meet condition are deleted

Viewed 64

Basically what the title says, Im trying to delete all names that have numbers in the string, what I was expecting from my code was:

['hello', 'number']

And what I got was:

['hello', 'number', 'Z23', 'Z46', 'U-557', 'U-81']

Here the code I'm using:

allnames1 = ['hello','Z18', 'number','Z20', 'Z23', 'Z28', 'Z46','U-101', 'U-557', 'U-73', 'U-81', 'U-96']
for name in allnames1:
    x = re.findall("\d",name)
    if len(x) != 0:
        allnames1.remove(name)
print(allnames1)

Why doesnt my code work as intended?

How can I modify the code for it to give me my expected output?

3 Answers

Since you're looping over the names in allnames1, but you're also removing elements from the list as you're looping over it, Python loses track of where it is in the list and skips one every time you remove one. A better solution would be to use a list comprehension like this:

import re

allnames1 = ['hello','Z18', 'number','Z20', 'Z23', 'Z28', 'Z46','U-101', 'U-557', 'U-73', 'U-81', 'U-96']
allnames1 = [name for name in allnames1 if len(re.findall("\d",name)) == 0]
print(allnames1)

There's more efficient ways to check there's no numbers there, but I kept as close as possible to your solution to show the idea.

As pointed out in other answer, you should not be removing elements from a list while iterating it. It looks to be a good candidate for filter function

>>> import re
>>> allnames = ['hello','Z18', 'number','Z20', 'Z23', 'Z28', 'Z46','U-101', 'U-557', 'U-73', 'U-81', 'U-96']
>>> names_filtered = list(filter(lambda x: not bool(re.search("\d",x)), allnames))
>>> names_filtered
['hello', 'number']

As mentioned already, do not modify the object you are iterating over. Otherwise, use list comprehension.

>>> import re
>>> l = ['hello', 'number', 'Z23', 'Z46', 'U-557', 'U-81']
>>> [i for i in l if not re.search(r"\d", i)]
['hello', 'number']
Related