Pythonリストを巡回するときに要素を削除

1861 ワード

本文は私の個人ブログSuixin’s Blogの原文に先発します:https://suixinblog.cn/2019/03/remove-for-list.html作者:Suixin
Pythonのforループはリストを巡回できますが、条件に合致する要素を同時に削除する必要がある場合はエラーが発生します.
エラー
s = [1, 2, 3, 4, 1, 1]
s1 = s
for i in s1:
    if i == 1:
        s1.remove(i)
print(s1)

出力:
[2, 3, 4, 1]

もう1つ:
s2 = s
for idx in range(len(s2)):
    if s2[idx] == 1:
        del s2[idx]
print(s2)

出力:
Traceback (most recent call last):
  File "temp.py", line 11, in 
    if s2[idx] == 1:
IndexError: list index out of range

エラーの原因
Pythonではforで任意の形式の遍歴を開始し、その遍歴順序は最初から決定され、遍歴で要素を削除すると現在のインデックスの変化を招くため、遍歴の間に取られたインデックスの値が変化し、いくつかの要素が漏れてしまいます.もう1つのエラーは、要素を削除するとリストの長さが縮小するため、インデックスの範囲を超えます.
正しい削除法
  • filter()関数を使用して、指定された条件を満たす要素をフィルタします.
    s3 = s
    print(list(filter(lambda x: x != 1, s3)))
    
    ここでlambdaはPythonにおける関数の簡略定義形式である.
  • リスト解析式を使用します.
    s4 = [i for i in s if i != 1]
    print(s4)
    
  • オリジナルリストを新しいリストにコピーし、新しいリストを巡り、オリジナルリストを変更します(または逆).
    s6 = s
    for i in s6[:]:
        if i == 1:
            s6.remove(i)
    print(s6)
    
    しかし、新しい変数と元の変数の物理アドレスが同じであるため、次の付与操作は新しいリストにはできません.id()関数で表示できます.
    s5 = s
    for i in s:
        if i == 1:
            s5.remove(i)
    print(s5)
    
    は、深いコピーによって上記の問題を解決することができる:
    import copy
    
    s5 = copy.deepcopy(s)
    for i in s:
        if i == 1:
            s5.remove(i)
    print(s5)
    
  • whileサイクルで判断条件を行う.
    s7 = s
    while 1 in s7:
        s7.remove(1)
    print(s7)
    

  • 上記4つの方法の出力はいずれも[2, 3, 4]であった.
    リファレンス
    https://segmentfault.com/a/1190000007214571 http://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html