

li2の中にある要素をliから除外したいと考えています。  
実行するとli=[4]としようとしていますが，li=[2,4]となってしまいます．  
よろしくお願いします。

[code]

    li=[1,2,3,4]
    li2=[1,2,3]
    
    for i in li:
        if i in li2:
            li.remove(i)
    
    print(li)
    
[/code]


CC BY-SA 3.0
2016-01-19T09:57:14.663
21070
2016-01-19T11:14:55.120
14061
question
python
Pythonで1次元のリストを比較し，同一の要素の削除について


forは対象リストのi番目を順に見ていくだけで、対象リストが書き換わっても知ったこっちゃないようです。  
li[:]の様にして同じ内容の別オブジェクトを用意するとおもったとおり動きます。  
<http://docs.python.jp/2.7/reference/compound_stmts.html#the-for-statement>

> 注釈
>
> ループ中のシーケンスの変更には微妙な問題があります ( これは変更可能なシーケンス、すなわちリストで起こります )
> 。どの要素が次に使われるかを追跡するために、内部的なカウンタが使われており、このカウンタは反復処理を行うごとに加算されます。このカウンタがシーケンスの長さに達すると、ループは終了します。このことは、スイート中でシーケンスから現在の
> ( または以前の ) 要素を除去すると、 ( 次の要素のインデクスは、すでに取り扱った要素のインデクスになるために )
> 次の要素が飛ばされることを意味します。同様に、スイート中でシーケンス中の現在の要素以前に要素を挿入すると、ループ中で現在の要素が再度扱われることになります。こうした仕様は、厄介なバグになります。シーケンス全体に相当するスライスを使って一時的なコピーを作ると、これを避けることができます。
[code]

>     for x in a[:]:
>         if x < 0: a.remove(x)
>  
[/code]


CC BY-SA 3.0
2016-01-19T10:07:10.553
21071
2016-01-19T10:07:10.553
10685
21070
answer


新しくリストオブジェクトを作るようにしたほうがコード的にシンプルになります。

[code]

    list(filter(lambda x:x not in li2, li))
    [4]
    
[/code]

または

[code]

    list(x for x in li if x not in li2)
    
[/code]

あと、細かいことですが、li2 を集合にしたほうが理論上は速くなります。

[code]

    li=[1,2,3,4]
    s={1,2,3}
    
    li = list(filter(lambda x:x not in s, li))
    
    print(li)
    [4]
    
[/code]

liやli2が大きくなる場合は集合の利用を検討してみてください。


CC BY-SA 3.0
2016-01-19T11:07:59.537
21073
2016-01-19T11:14:55.120
2016-01-19T11:14:55.120
13227
13227
21070
answer