Python循环陷阱-删除
使用数组循环删除时引发的问题
Demo Debug
Demo1
正常循环数组,一共有6个元素,从索引0开始到索引5结束(下图为未开始循环)
当循环第一次的时,i=1,即list_1[1]取得2,进入if判断ture并删除;循环第二次时,i=2,即list_1[2]取得4(下图为循环第2次)
当第五次循环时,i=5,即list_1[5],数组越界报错IndexError,(下图为循环第5次)
由此可见,触发删除元素时list_1[1]=2变为list_1[1]=3,后面的元素下标索引全部前进一位,补充删除的位置,同时位数-1
Demo2
正常循环数组,一共有6个元素,从索引0开始到索引5结束(下图为第1次循环,未删除)
第一次循环结束并删除第一个元素后,进入循环第二次判断,可见list_2[0]=1变成list_2[0]=2, 与Demo1一样全部元素前进一位
循环第三次,下标索引为2,获得i=5,执行完成后,因数组长度为3,已遍历完毕,打印[2, 4, 6]
由此可见,每次删除一个元素,该元素后面的元素都会向前一位,同时数组长度-1,Demo2的循环删除数组也不会清空,因前进一位躲过一劫,数组长度为原长度的1/2
解决方法
方法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: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原数组
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)