0%

Python循环陷阱-删除

Python循环陷阱-删除

使用数组循环删除时引发的问题

Demo Debug

  1. Demo1

    • 正常循环数组,一共有6个元素,从索引0开始到索引5结束(下图为未开始循环)
      Image text

    • 当循环第一次的时,i=1,即list_1[1]取得2,进入if判断ture并删除;循环第二次时,i=2,即list_1[2]取得4(下图为循环第2次)
      Image text

    • 当第五次循环时,i=5,即list_1[5],数组越界报错IndexError,(下图为循环第5次)
      Image text

      由此可见,触发删除元素时list_1[1]=2变为list_1[1]=3,后面的元素下标索引全部前进一位,补充删除的位置,同时位数-1

  2. Demo2

    • 正常循环数组,一共有6个元素,从索引0开始到索引5结束(下图为第1次循环,未删除)
      Image text

    • 第一次循环结束并删除第一个元素后,进入循环第二次判断,可见list_2[0]=1变成list_2[0]=2, 与Demo1一样全部元素前进一位
      Image text

    • 循环第三次,下标索引为2,获得i=5,执行完成后,因数组长度为3,已遍历完毕,打印[2, 4, 6]
      Image text

      由此可见,每次删除一个元素,该元素后面的元素都会向前一位,同时数组长度-1,Demo2的循环删除数组也不会清空,因前进一位躲过一劫,数组长度为原长度的1/2

解决方法

  1. 方法1:反向遍历

    1
    2
    3
    4
    5
    # 问题二
    list_2 = [1, 2, 3, 4, 5, 6]
    for i in list_2[::-1]:
    list_2.remove(i)
    print(list_2) # []

    使用反向遍历,每次删除元素都会向前,而每次遍历都是最后一位开始,则可以正常遍历所有元素

  2. 方法2:copy一个临时数组,用于遍历

    1
    2
    3
    4
    5
    6
    # 问题二
    list_2 = [1, 2, 3, 4, 5, 6]
    list_tmp = list_2.copy()
    for i in list_tmp:
    list_2.remove(i)
    print(list_2) # []

    使用copy()方法复制出一个临时数组list_tmp,循环遍历list_tmp,操作则使用list_2原数组

  3. Demo1的解决方法也可以方法2的copy临时数组处理

    1
    2
    3
    4
    5
    6
    7
    8
    # 问题一
    list_1 = [1, 2, 3, 4, 5, 6]
    list_tmp = list_1.copy()
    for i in range(len(list_tmp)):
    if list_tmp[i] == 2:
    list_1.pop(i)

    print(list_1) # [1, 3, 4, 5, 6]

总结

python的数组循环删除会直接影响或打乱下标索引的位置,若删除元素应尽量避免使用下标索引获取元素,且copy临时数组的性能比较糟糕,建议使用反向循环(即方法1)