発端
ある日pythonコードを書いてると,変なことが起こった…
x = [1, 2, 3, 4, 5]
for i in x:
x.remove(i)
print(x)
>>>
[2, 3, 4, 5] # わかる
[2, 4, 5] # ???1抜いて2抜いたら[3, 4, 5]では!?!?
[2, 4] # ???????
ちなみにrubyで試してみても同じだった.
x = [1, 2, 3, 4, 5]
for i in x do
x.delete(i)
print(x)
end
>>>
[2, 3, 4, 5][2, 4, 5][2, 4] => [2, 4]
どうも,「for i in x」というのは,
- i = x[0] # [1, 2, 3, 4, 5]の"1"
- i = x[1] # [2, 3, 4, 5]の"3"
- i = x[2] # [2, 4, 5]の"5"
のように,ループをの度にxの0, 1, 2, ..., n番目を参照しようとしているらしい.
対策
[:]やcopy()でリストをコピーしておくとよい
x = [1, 2, 3, 4, 5]
for i in x[:]:
x.remove(i)
print(x)
>>>
[2, 3, 4, 5]
[3, 4, 5]
[4, 5]
[5]
[]
from copy import copy
x = [1, 2, 3, 4, 5]
for i in copy(x):
x.remove(i)
print(x)
>>>
[2, 3, 4, 5]
[3, 4, 5]
[4, 5]
[5]
[]
あとがき
30分ぐらい「うーん,うーん…」って悩んでました.
numpyでゴリ押ししてると標準リストの破壊的メソッドに惑わされますね…