1. ホーム
  2. python

ループが一部の項目を削除するのを「忘れる」 [重複] [重複

2023-08-02 14:02:47

質問

このコードでは、私は文字列からすべての母音(aeiouAEIOU)を削除する関数anti_vowelを作成しようとしています。私はそれを考える べきである はうまくいくはずですが、私がそれを実行すると、サンプルテキスト "Hey look Words!" は "Hy lk Words!" として返されます。最後の'o'を削除するのを忘れているのです。どうしてでしょうか?

text = "Hey look Words!"

def anti_vowel(text):

    textlist = list(text)

    for char in textlist:
        if char.lower() in 'aeiou':
            textlist.remove(char)

    return "".join(textlist)

print anti_vowel(text)

どのように解決するのですか?

反復処理中のリストを変更しているので、直感的でない動作になるはずです。代わりに、リストのコピーを作成し、反復処理中のものから要素を削除しないようにします。

for char in textlist[:]: #shallow copy of the list
    # etc


あなたが見ている動作を明確にするために、これをチェックしてみてください。プット print char, textlist を(元の)ループの最初に置いてみてください。おそらく、これでリストと一緒に文字列が垂直に出力されると期待するでしょうが、実際に出力されるのは次のようなものです。

H ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
e ['H', 'e', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
  ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # !
l ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
o ['H', 'y', ' ', 'l', 'o', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
k ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] # Problem!!
  ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
W ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
o ['H', 'y', ' ', 'l', 'o', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!'] 
d ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
s ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
! ['H', 'y', ' ', 'l', 'k', ' ', 'W', 'o', 'r', 'd', 's', '!']
Hy lk Words!

で、どうなってるんだ?素敵な for x in y ループは実際には単なる構文上の糖分です:それはまだインデックスによってリスト要素にアクセスします。そのため、反復処理中にリストの要素を削除すると、(上で見たように)値をスキップするようになります。その結果、2番目の o"look" というのは、前の要素を削除したときに、インデックスがそれを越えて進んでしまったからです。そして o"Words" を削除する場合、最初に現れる 'o' を削除します。


他の人が言及したように、リスト内包はおそらくこれを行うためのさらに良い(よりきれいで、より明確な)方法でしょう。Pythonの文字列が反復可能であるという事実を利用します。

def remove_vowels(text): # function names should start with verbs! :)
    return ''.join(ch for ch in text if ch.lower() not in 'aeiou')