Help us understand the problem. What is going on with this article?

ループ対象のlistをremoveすると酷い目に遭う

More than 3 years have passed since last update.

発端

ある日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でゴリ押ししてると標準リストの破壊的メソッドに惑わされますね…

mytk0u0
ほぼ全ての記事を手探りで得た知見の共有として書いています。間違っていたり非効率だったりするものもあるかと思います。その場合はご指摘いただけると嬉しいです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away