何が起きた
リスト内に削除する要素が複数あり、何も考えずにループしながら削除して行ったら条件に一致するのに削除されない要素が見つかった。
原因
至ってシンプルで、リストの先頭から走査して削除したため、インデックスと要素の組み合わせがおかしくなり、本来削除される要素が残ってしまった。
対処方法
リストを逆順から走査するよう変更
対処前
lst = [1, 2, 3]
for i in lst:
if i in (1, 2):
lst.remove(i)
print(lst)
# 実行結果
[2, 3]
対処後
lst = [1, 2, 3]
for I in reversed(lst):
if i in (1, 2):
lst.remove(i)
print(lst)
# 実行結果
[3]
解説
リストの頭から削除すると要素が詰められるがインデックスはそのまま。
このため削除された次の要素が詰められてしまい処理されない。
リストを後ろから削除することで次に判定される要素が詰められることを防ぐ。
検証
対応前
>>> lst = [1, 2, 3]
>>> for i, l in enumerate(lst):
... print("index:%s, value:%s, list:%s" % (i, l, lst))
... if l in (1, 2):
... lst.remove(l)
... print("index:%s, value:%s, list:%s" % (i, l, lst))
...
index:0, value:1, list:[1, 2, 3]
index:0, value:1, list:[2, 3]
index:1, value:3, list:[2, 3]
index:1, value:3, list:[2, 3]
indexが1の時点でvalueが3になっているため、本来であれば判定で除去されなければならない2が処理されていない。(元のリスト通りならindexが1の時、valueは2)
これを逆順で行う。
対応後
>>> lst = [1, 2, 3]
>>> for i, l in enumerate(reversed(lst)):
... print("index:%s, value:%s, list:%s" % (i, l, lst))
... if l in (1, 2):
... lst.remove(l)
... print("index:%s, value:%s, list:%s" % (i, l, lst))
...
index:0, value:3, list:[1, 2, 3]
index:0, value:3, list:[1, 2, 3]
index:1, value:2, list:[1, 2, 3]
index:1, value:2, list:[1, 3]
index:2, value:1, list:[1, 3]
index:2, value:1, list:[3]
気をつけるべき事柄
ここまでは要素で削除を行った場合。
気をつけなければならないのは、インデックスで削除を行う場合。
インデックスで削除する場合、この書き方ではエラーになってしまう。
>>> lst = [1, 2, 3]
>>> for i, l in enumerate(reversed(lst)):
... print("index:%s, value:%s, list:%s" % (i, l, lst))
... if l in (1, 2):
... del lst[i]
... print("index:%s, value:%s, list:%s" % (i, l, lst))
...
index:0, value:3, list:[1, 2, 3]
index:0, value:3, list:[1, 2, 3]
index:1, value:2, list:[1, 2, 3]
index:1, value:2, list:[1, 3]
index:2, value:1, list:[1, 3]
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
IndexError: list assignment index out of range
この場合は以下の以下のようにすれば対応できる。
>>> lst = [1, 2, 3]
>>> for i, l in reversed(list(enumerate(lst))):
... print("index:%s, value:%s, list:%s" % (i, l, lst))
... if l in (1, 2):
... del lst[i]
... print("index:%s, value:%s, list:%s" % (i, l, lst))
...
index:2, value:3, list:[1, 2, 3]
index:2, value:3, list:[1, 2, 3]
index:1, value:2, list:[1, 2, 3]
index:1, value:2, list:[1, 3]
index:0, value:1, list:[1, 3]
index:0, value:1, list:[3]