2016-10-02 128 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)