本文以列表作爲示例,講述爲什麼在循環體中不能使用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