2011-12-17 4 views
8

私が基本的に必要とするのは、リストのすべての要素をチェックし、いくつかの条件が満たされていればそれをリストから削除したいのです。例えばのでPythonのループのイテレータをループ内から正しく変更する方法

原則として(のは

リスト= [ 'A'、 'B'、 'C​​'、 'D'、 'E']

が、私は基本的に書きたいとしましょうと

リストの要素が 'b'または 'c'の場合は、リストから削除して次の要素を取ります。 「B」が削除されたときに、ループが次の要素として、「D」としない「C」をとるため

しかし

for s in list: 
    if s=='b' or s=='c': 
     list.remove(s) 

は失敗します。それで、要素を別のリストに格納して後で削除するよりも速く行う方法がありますか?

ありがとうございました。

答えて

9

簡単な方法は、リストのコピーを使用することです - それは、リストの「最後」に「初めから」拡張スライスで行うことができ、このように:

for s in list[:]: 
    if s=='b' or s=='c': 
     list.remove(s) 

あなたはこれを考慮しました。これは、このリストが本当に大きく、コードの重要な部分(アクションゲームのメインループのようなもの)でない限り、あなたのコードに入るほど簡単です。あなたが代わりにwhileループに頼ることができます。もちろん、

to_remove = [] 
for index, s in enumerate(list): 
    if s == "b" or s == "c": 
     to_remove.append(index) 

for index in reversed(to_remove): 
    del list[index] 

:その場合は、私は時々、次のイディオムを使用

index = 0 
while index < len(list): 
    if s == "b" or s == "c": 
     del list[index] 
     continue 
    index += 1 
+0

jsbuenoをどうもありがとうございました。私はそれを考えないと少し恥ずかしい気がする。再度、感謝します! – tst

+0

私はループ内で実際にループを望んでいて、最後の例は完璧でした。再度、感謝します。 – tst

1

あなたがリストのコピーを作成して[O​​K]をしている場合は、あなたが行うことができますそれのように、この(list comprehension):

[s for s in list if s != 'b' and s != 'c'] 
8

その良く、すでに利用可能なものを改革することはありません。これらの場合は、filterの関数とlambdaを使用してください。そのより多くのpythonicと見た目クリーナー。

filter(lambda x:x not in ['b','c'],['a','b','c','d','e']) 

代わりに、あなたはこれがitertools.ifilterがために設計されている正確に何であるリストの内包

[x for x in ['a','b','c','d','e'] if x not in ['b','c']] 
+0

実際、2番目の例のリストの理解は、フィルターとラムダの組み合わせよりも「Pythonic」です。 – jsbueno

+0

ありがとうございましたが、私はそのようなループを他に入れておく必要がありました。 – tst

3

を使用することができます。

from itertools import ifilter 

ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e']) 

あなたのリストのジェネレータを返します。あなたが実際にリストが必要な場合は、リストに発電機を変換するための標準的な技術の1つを使用して、それを作成することができます。

list(ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])) 

または

[x for x in ifilter(lambda x: x not in ['b', 'c'], ['a', 'b', 'c', 'd', 'e'])] 
関連する問題