本文以列表作为示例,讲述为什么在循环体中不能使用pop()函数和remove()函数。
出现的问题
一般地,删除列表中的一个元素有pop()
和remove()
方法。例如下面的例子:
lst = [1, 2, 3, 4 ,5]
print(lst)
lst.pop()
print(lst)
lst.remove(1)
print(lst)
结果为
[1, 2, 3, 4, 5]
[1, 2, 3, 4]
[2, 3, 4]
但是在循环体中不能怎么做,列表循环一般有两种方式,一种是for i in range(len(lst))
,另外一种是for item in lst
。
- 第一种循环
num_list = [1, 2, 3, 4, 5]
print(num_list)
for i in range(len(num_list)):
if num_list[i] == 2:
num_list.pop(i)
else:
print(num_list[i])
print(num_list)
输出结果
[1, 2, 3, 4, 5]
1
4
5
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-25-7e590a65a8c9> in <module>
3
4 for i in range(len(num_list)):
----> 5 if num_list[i] == 2:
6 num_list.pop(i)
7 else:
IndexError: list index out of range
可以看到程序报错,出错的原因是当删除了列表中的元素2
时,num_list
的长度变为了4,所以在循环到最后一个元素的时候,会提示下标超出范围。
- 第二种循环
num_list = [1, 2, 3, 4, 5]
print(num_list)
for item in num_list:
if item == 2:
num_list.remove(item)
else:
print(item)
print(num_list)
输出结果为
[1, 2, 3, 4, 5]
1
4
5
[1, 3, 4, 5]
奇怪的发现,元素3
怎么丢失了?其实这和python循环中的迭代器有关,当迭代器到达num_list
中的第二个元素2
的时候,将其删除,然后迭代器将会自动的指向列表的下一个元素,由于这时候已经删除了第二个元素,所以迭代器便指向了新数组的第3个元素也就是4,所以出现了上述的情况,下面的图可以比较清晰的解释上面的过程。
仔细观察可以发现,虽然上述的结果中间打印的时候漏掉了一个元素,对最终的结果没有什么影响,但是这只是一种比较幸运的情况,比如下面的例子就没那么幸运了。
x = ['a', 'b', 'c', 'd']
y = ['b', 'c']
for i in x:
if i in y:
x.remove(i)
print(x)
输出结果为
['a', 'c', 'd']
按照正常的理解,应该最终的结果为['a', 'd']
,但是最终结果却多了一个'c'
,我们根据上述的迭代图进行分析,当遍历到列表x
的'b'
元素时,判断条件成立,删除列表x
中的'b'
元素,这是列表x=['a', 'c', 'd']
,但此时的迭代器位于列表的第三个元素,也就是新列表x
的'd'
元素,直接把'c'
忽略掉了,所以最终结果才会出现'c'
。
解决方法
要想解决这个问题,一种方法自然是定义一个新的数组,将结果存到新数组中,或者从后面往前面遍历,这时候也可以避免上述漏掉元素的情况。
- 方法1:定义一个新的列表
x = ['a', 'b', 'c', 'd']
y = ['b', 'c']
new_list = list()
for i in x:
if i in y:
x.remove(i)
else:
new_list.append(i)
print(new_list)
- 方法2:从后面往前遍历列表
x = ['a', 'b', 'c', 'd']
y = ['b', 'c']
for i in range(len(x) - 1, -1, -1):
if x[i] in y:
x.pop(i)
print(x)
两种方法的输出结果都一样
['a', 'd']
不过还是建议使用第一种方法,虽然更占内存,但是简洁易懂,也容易对新列表进行操作。
参考
https://www.cnblogs.com/bananaplan/p/remove-listitem-while-iterating.html
https://kyle.ai/blog/6565.html