NaNCat
NaNCat

Reputation: 109

Why is Python not removing this character?

This is my first experience with Python. I'm following an exercise out of the Head First Python book. I'm trying to convert one string into another string. (Changing "Don't panic!" into "on tap".) First, I convert the string into a list. Then, I use an if statement in a for loop to filter out the letters that I don't need.

I'm getting some very strange behavior, though! Here's my code:

phrase = "Don't panic!"
plist = list(phrase)
print(phrase)
print(plist)

for character in plist:
    if character not in ['o', 'n', 't', 'a', 'p', ' ']:
        plist.remove(character)
        print("removing ", character)
new_phrase = ''.join(plist)
print(plist)
print(new_phrase)

And here's my output:

Don't panic!
['D', 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!']
removing  D
removing  '
removing  i
removing  !
['o', 'n', 't', ' ', 'p', 'a', 'n', 'c']
ont panc

Why is the letter "c" still there? It's not in the array that I used in the if statement, and the rest of the characters get filtered out. But not the "c". Why?

Upvotes: 1

Views: 547

Answers (3)

RufusVS
RufusVS

Reputation: 4127

To show what I was suggesting in my comment, here's your code, modified:

phrase = "Don't panic!"
plist = list(phrase)
print(phrase)
print(plist)
removable = []
for character in plist:
    if character not in ['o', 'n', 't', 'a', 'p', ' ']:
        removable.append(character)
for character in removable:
        plist.remove(character)
        print("removing ", character)
new_phrase = ''.join(plist)
print(plist)
print(new_phrase)

(Actually, you would be better off making removable a set, to eliminate duplicate entries, but I leave that as an exercise.)

This was my comment, which I should have quoted in this answer:

It is generally not a good idea to modify the list that you are iterating over (that is in the for statement). You are not likely to get the expected results (you'll learn more when you get more comfortable with iterators and such). You are better off creating a list of removable letters in the first pass, then do another loop that will remove those letters from the list.

Upvotes: 1

Robin
Robin

Reputation: 1

You need to loop over the phrase.

phrase = "Don't panic!"
plist = list(phrase)
print(phrase)
print(plist)

for character in phrase:
    if character not in ['o', 'n', 't', 'a', 'p', ' ']:
        plist.remove(character)
        print("removing ", character)
new_phrase = ''.join(plist)
print(plist)
print(new_phrase)

result

Don't panic!
['D', 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!']
removing  D
removing  '
removing  i
removing  !
['o', 'n', 't', ' ', 'p', 'a', 'n', 'c']
ont pan

The problem was after you remove a char from the list like: 'D, i' the next character will we skipped. You can test that if you remove the 'o' from the not-in array. Should have no effect on the output.

Upvotes: 0

sahasrara62
sahasrara62

Reputation: 11238

why this behaviour ?

first you are deleting a list whose generate object is looping in the for loop. making the list dynmic. so whenever you delete a index from a list lets say D , 0th index, then [ 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] this becomes your list.

now since generator object when deleting D was at index 0, then next(object) would point to 1st index of remaining list. so that would be 'n value. Note it didn't go through the o at newly updated index. this same happens when it passes through the c.

to verify this here is a result code

plist = list(phrase)
print(phrase)
print(plist)

for index, character in enumerate(plist):
    print(plist, character, index)
    if character not in ['o', 'n', 't', 'a', 'p', ' ']:
        plist.remove(character)
        # print("removing ", character)
new_phrase = ''.join(plist)
print(plist)
print(new_phrase)

result

Don't panic!
['D', 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!']
['D', 'o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] D 0
['o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] n 1
['o', 'n', "'", 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] ' 2
['o', 'n', 't', ' ', 'p', 'a', 'n', 'i', 'c', '!']   3
['o', 'n', 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] p 4
['o', 'n', 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] a 5
['o', 'n', 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] n 6
['o', 'n', 't', ' ', 'p', 'a', 'n', 'i', 'c', '!'] i 7
['o', 'n', 't', ' ', 'p', 'a', 'n', 'c', '!'] ! 8
['o', 'n', 't', ' ', 'p', 'a', 'n', 'c']
ont panc

you can see how list is behaving when a value is deleted

Upvotes: 2

Related Questions