1. 程式人生 > >Python列表邊遍歷邊修改問題解決方案:alist[:]

Python列表邊遍歷邊修改問題解決方案:alist[:]

不同 com false function 猜想 目標 但是 結果 tro

最近在看python,遇到個簡單的問題:刪除列表中指定的重復元素,發現一些實用並且有趣的東西。

1.錯誤示範

alist = [1,1,2,2,3,3,2,2,1,1]
for i in alist:    
    if i ==1:
        alist.remove(1)
print(alist)

運行結果:[2, 2, 3, 3, 2, 2, 1, 1]
錯誤原因:刪除列表元素,導致列表內容改變,部分元素位置前移;當繼續進行for循環時,索引繼續加一,導致跳過一個元素。
本例中,第二個“1”和第四個“1”被跳過,但是remove()是刪除從列表第一個出現的元素,所以當第三個“1”出現進入if語句時,第二個“1”被刪除。

2.解決方法一:alist[1]

alist = [1,1,2,2,3,3,2,2,1,1]
for i in alist[:]:                ###
    if i ==1:
        alist.remove(1)
print(alist)

運行結果:[2, 2, 3, 3, 2, 2]
簡析:將for循環中的控制語句改成" for i in alist[:]"後,程序正確實現功能。對於這個很神奇的alist[:],查了好久,都沒有找到相關資料。後來,在和朋友的討論中,我突然想到“地址”的抽象概念。錯誤實現的語句" for i in alist"中的"alist",是列表的名稱,類似於C中的數組名,其實可以看做一個指向該列表的指針,執行for循環時不斷地通過這個地址找到對應元素,導致出現錯誤結果。
然而," for i in alist[:]"中,“alist[:]”是將alist中的所有元素取出,存儲在另一塊獨立與alist的區域中,這樣的話,當修改原列表alist時,並不會修改for循環的判斷邏輯,其實就是相當於alist復制給一個新的列表,利用新的列表進行for循環的控制。
為驗證以上猜想,用id()命令分別查看alist 和 alist[:]的地址,果然不同。
技術分享圖片

3.解決方案二:定義一個新的列表

alist = [1,1,2,2,3,3,2,2,1,1]
alist_new = []
for i in alist:
    if i!=1:
        alist_new.append(i)
alist = alist_new
print  (alist)

運行結果:[2, 2, 3, 3, 2, 2]
簡析:定義一個新的列表,將不滿足條件的值添加到新表中,遍歷原列表後,將新列表覆蓋原列表。
缺點:新列表會占用內存

4.解決方法三:改變循環條件

alist = [1,1,2,2,3,3,2,2,1,1]
i = 0
while i<len(alist):
    if alist[i]==1:
        alist.pop(i)
        i = i-1
    i = i+1
print (alist)

運行結果:[2, 2, 3, 3, 2, 2]
簡析:改變循環條件,判斷是否遍歷完成,如果刪除一個元素,後面元素前移,此時令循環條件i減1,再次判斷當前位置,正好判斷的是後移過來的新元素。直到所有元素全部遍歷。
缺點:邏輯稍復雜,比較優化

5.解決方法四:利用while循環和in、index()函數

alist = [1,1,2,2,3,3,2,2,1,1]
while 1 in alist :
    alist.pop(alist.index(1))
print (alist) 

運行結果:[2, 2, 3, 3, 2, 2]

簡析:(1)關鍵字in,判斷一個元素是否在一個集合中,返回True/False;同理,not in也是判斷一個元素是否不在一個集合中,返回True/False;有一個類似的關鍵字 is,判斷兩個變量是否是同一對象,即同一內存空間,或者地址相同,同樣有not is。
(2)index()方法,返回元素在序列中第一次出現的索引號,如果元素不存在於序列中,則會報出異常。
(3)pop() 函數用於移除列表中的一個元素(可用需要刪除的索引號作為輸入參數,默認刪除最後一個元素),並且返回該元素的值。
(4)邏輯:在while條件中不斷判斷列表中是否有目標元素,若有,則用index()找到該元素的索引號,並用pop()刪除,直到刪除幹凈。

6.解決方法五:利用filter()和labmbda

alist = [1,1,2,2,3,3,2,2,1,1]
alist = list(filter(lambda x: x!=1, alist))
print (alist)

運行結果:[2, 2, 3, 3, 2, 2]
簡析:(1)根據題目要求,就是對列表進行過濾處理,很自然地想到了filter()函數,配合lambda表達式簡直完美。
(2)filter()函數:用於過濾序列,過濾掉不符合條件的元素,返回由符合條件元素組成的新列表。該接收兩個參數,第一個為函數,第二個為序列,序列的每個元素作為參數傳遞給函數進行判,然後返回 True 或 False,最後將返回 True 的元素放到新列表中。
用法:filter(function, iterable)
(3)lambda:匿名定義簡單函數,主體是一個表達式,常用於函數式編程。
用法:lambda [arg1 [,arg2,.....argn]]:expression
(4)邏輯:用lambda定義匿名函數,判斷元素是否為非“1”,若真則返回True,否則返回False。在用filter函數進行過濾處理,實現對列表的過濾功能。

Python列表邊遍歷邊修改問題解決方案:alist[:]