2011-02-10 8 views
5

リストをループして、条件を満たす要素を削除します。しかし、なぜ、これは以下のように動作しませんか?ありがとうございました。Pythonのリストから要素を安全に削除する方法

>>> a=[ i for i in range(4)] 
>>> a 
[0, 1, 2, 3] 
>>> for e in a: 
...  if (e > 1) and (e < 4): 
...   a.remove(e) 
... 
>>> a 
[0, 1, 3] 
>>> a=[ i for i in range(4)] 
>>> for e in a: 
...  if (e > -1) and (e < 3): 
...   a.remove(e) 
... 
>>> a 
[1, 3] 

答えて

9

あなたが反復処理中に何かを変更することはできません。結果は奇妙で逆らって直感的で、ほとんどあなたが望むものではありません。実際、多くのコレクションでは、これを明示的に禁止しています(例:集合や辞書)。

代わりに、コピー(for e in a[:]: ...)を繰り返したり、既存のリストを変更する代わりにフィルタを適用して、必要な項目([e for e in a if ...])を含む新しいリストを取得します。多くの場合、フィルタリングを再度繰り返す必要はなく、フィルタリングをデータの生成とマージするだけです。

5

リストの理解の初めにこれをやってみませんか?例えば。

[i for i in range(4) if i <= 1 or i >= 4] 

これを使用して、既存のリストから新しいリストを作成することもできます。

[x for x in a if x <= 1 or x >= 4] 
+0

実際に削除する必要があるアイテムを返します。 –

+0

@Sven申し訳ありません、私はそれを修正します –

1

それを繰り返しながらリストから要素を削除することは安全ではありません。そのためには、フィルタ関数が存在します。これは関数(1つの引数を受け入れる)と繰り返し可能(この場合はあなたのリスト)を受け取ります。

a = filter(lambda x: x > 1 and x < 4, range(4)) 

:あなたはこのようなラムダ関数を使用することができますあなたのケースでは

:それはその要素に適用される関数がTrueを返された要素と同じタイプの新しい反復可能(ここで再びリスト)を返します。または既にリストがある場合:

a = range(4) 
a = filter(lambda x: x > 1 and x < 4, a) 

python3を使用している場合は、リストではなくイテレータを返します。

+0

このような単純なケースでは、私は 'filter'を介してリストの理解を望むでしょう。 –

2

フィルタリングのアイデアは良いですが、いくつかのリストが非常に大きく、削除する要素の数が非常に少ないかもしれないという点が欠けています。

答えは、削除する要素のリストインデックスを覚えておいてから、インデックスのリストを反復して、最大から最小にソートして要素を削除することです。

+0

要素リストが100万個あり、4個が削除されたとします。それをフィルタリングするということは、およそ1,000,000要素をシャッフルすることを意味しますが、あなたの提案は平均して約2倍のシャフリングを伴うことになります。もちろん、それ以外の要素はそれほど単純ではありませんが、コードを実際にタイムアウトしていない限り、単純な複合体。 – Duncan

+0

私は要素を「シャッフルする」とは考えていません。最後に、逆の順序で反復する4つの要素のリストがあります。削除にはリスト要素のリンクを解除する必要があります。シャッフルはどこですか? –

2

視覚化する最も簡単な方法は、実際のアイテムの代わりにリストオフセットを処理する反復を考えることです。アイテムがなくなるまで、最初のアイテム、次に2番目のアイテム、3番目のアイテムを実行します。 。あなたはそのようにそれをステップ場合は理にかなって

1 
4 
[1,3,4] 

lst = [1,2,3,4] 
for item in lst: 
    if item==2: 
     lst.remove(item) 
    else: 
     print item 
print lst 

結果:あなたは、リスト内の項目数を変更する場合は、リスト内のすべての残りの項目のオフセットを変更します:

[1,2,3,4] 
^ 
first item is not 2, so print it -> 1 

[1,2,3,4] 
^
    second item is 2, so remove it 

[1,3,4] 
    ^
    third item is 4, so print it -> 4 

唯一の真の解決策は、あなたがそれを反復している間、リスト内の項目数を変更しないでくださいです。保持するアイテムを新しいリストにコピーするか、削除する値を追跡し、別のパスで値の削除を実行します。

+0

+1は厄介な詳細を説明します。 – delnan