2016-10-02 93 views
2

我在Python的edx在線課程,我必須做這個小程序,我認爲該函數是正確的,但它有錯誤時,一個元素從列表中刪除突然下一個元素不考慮進入測試。python函數的奇怪行爲

def f(i): 
     return i + 2 
    def g(i): 
     return i > 5 


    def applyF_filterG(L, f, g): 
     """ 
     Assumes L is a list of integers 
     Assume functions f and g are defined for you. 
     f takes in an integer, applies a function, returns another integer 
     g takes in an integer, applies a Boolean function, 
     returns either True or False 
     Mutates L such that, for each element i originally in L, L contains 
      i if g(f(i)) returns True, and no other elements 
     Returns the largest element in the mutated L or -1 if the list is empty 
     """ 
     # Your code here 
     i = 0 
     if len(L) == 0: 
      return -1 
     while i < len(L): 
      if not g(f(L[i])): 
       del L[i] 
      i += 1 
     return max(L) 

如果我嘗試這個例子L = [0,-10,5,6,-4,-2],L的值應爲L = [5,6],但其結果是這[-10,5,6,-2]當0被刪除時,元素-10被跳過,-4和-2發生同樣的情況。請幫忙,我不知道如何解決這個問題。

+2

長話短說:你永遠不想在迭代它的同時改變列表。 – elethan

+2

如果您確實想要在列表中迭代時刪除元素(即使這通常不是一個好主意),但最好的方法是從最大的索引開始,向最小的方向工作。這樣當一個元素被刪除時,它的刪除不會改變你仍然需要訪問的元素的任何索引。 –

回答

3

儘量不要通過你在Python循環內變異對列表進行迭代。在這個例子中,刪除元素後索引順序發生了變化。在迭代它之前,我創建了一個L的副本,它實現了這個訣竅。

def applyF_filterG(L, f, g): 
    copied_L = L[:] 
    for i in copied_L: 
     if not g(f(i)): 
      L.remove(i) 
    if len(L)==0: 
     return -1 
    else: 
     return max(L) 
+0

此代碼適用於任何情況,謝謝。我現在注意到我的錯誤是什麼。 – DiegoLl0895

2

在迭代列表時突變列表是一個壞主意,會導致意外的行爲。一般來說,你最好創建一個新的工作列表。

在這種特殊情況下,您的代碼可以通過簡單的修改來修復。只有在不刪除元素的情況下才迭代索引,以免在列表中跳過。

while i < len(L): 
    if not g(f(L[i])): 
     del L[i] 
    else: 
     i += 1 
+0

它解決了我的問題,非常感謝。我注意到現在我的問題是什麼。 – DiegoLl0895

3

問題:

,你遍歷列表你從列表中刪除元素。因此,i不再引用列表中的正確元素。

爲了說明這個問題,下面是一個運行你的代碼的例子。
對於這個例子,我們將假設if語句刪除一個元素,如果它的值是偶數。
我還假設i已經被初始化。

L = [1,2,6,3,4]

迭代1

我== 0,L [I] == 1,我們不刪除該元素。
大號== [1,2,6,3,4]

迭代2

我== 1,L [I] == 2,元素被刪除。
大號== [1,6,3,4]

迭代3

我== 2,L [I] == 3,我們不刪除的元素。
L == [1,6,3,4]
#你有沒有注意到我們只是跳過檢查6,因爲它的索引移動?!

迭代4

i == 3,L [i] == 4,元素被刪除。
L == [1,6,3]

我們完成了!


有幾個方法可以做到這一點。雖然@Meerness已經提供了一種方法來完成它,但這裏有另一種方法可以完成。

i = len(L) - 1 
if i == -1: 
    return -1 

while i >= 0: 
    if not g(f(L[i])): 
     del L[i] 
    i -= 1 

這是如何工作:

在做的這樣,你算從最上層的指數下跌。這樣,刪除元素不會影響尚未檢查的元素的索引。
我對這種做法的解釋是由@JohnColeman對該評論稍作修改。
JSYK,雖然我在看到他的評論之前已經寫了這個解決方案,所以我沒有借他的想法 - 我只是借用了他的解釋。 :)

下面是會發生什麼情況的例子,當我們倒計時代替向上計數的:

L = [1,2,6,3,4]

迭代1

i == 4,L [i] == 4,元素被刪除。
大號== [1,2,6,3]

迭代2

我== 3,L [I] == 3,我們不刪除的元素。
大號== [1,2,6,3]

迭代3

我== 2,L [I] == 6,元素被刪除。
大號== [1,2,3]

迭代4

我== 1,L [I] == 2,元素被刪除。
大號== [1,3]

迭代5

我== 0,L [I] == 1,我們不刪除的元素。
L == [1,3]

我們完成了!


PS:實例與python3腳本自動生成的。 :)

0
def applyF_filterG(L, f, g): 
    """ 
    Assumes L is a list of integers 
    Assume functions f and g are defined for you. 
    f takes in an integer, applies a function, returns another integer 
    g takes in an integer, applies a Boolean function, 
     returns either True or False 
    Mutates L such that, for each element i originally in L, L contains 
     i if g(f(i)) returns True, and no other elements 
    Returns the largest element in the mutated L or -1 if the list is empty 
    """ 

    M =[] 
    for i in range(len(L)): 
     if g(f(L[i])): 
      M.append(L[i]) 
    L = M[:] 
    if len(L)==0: 
     return -1 
    else: 
     return max(L)