首先想到你需要知道的是del L[i]删除了i元素。 (不要使用L.remove(L[i]);查找i元素,然后搜索整个列表,直到找到相等的值,然后删除它。)
但请注意,如果您删除L[3],然后转到L[4],则您已跳过一个值 - 原始L[4]现在为L[3],你仍然需要检查它。因此,在找到您要保留的值之前,您必须确保不要增加i。
但是,如果你只是循环遍历所有索引,并且你已经删除了一些索引,那么你将会跑到最后。因此,每次删除时都需要减小长度。或者您也可以继续再次呼叫len(L)并每次检查新长度。
一次解决这两个问题的一个聪明方法是向后计数,如Brad Budlong's answer。但这可以很容易地制造出fencepost错误。所以,我会以另一种方式做到这一点。
def rmNegative(L):
length = len(L)
i = 0
while i < length:
if L[i] < 0:
del L[i]
length -= 1
else:
i += 1
就是这样。
如果您想知道为什么现有代码是无限循环,请让我们逐步了解它的作用。
我们从pos=len(L)-1开始,因此我们进入了大elif。 pos=pos什么也没做。如果它是负数,则将其删除并转到新的len(L)-1;如果它是正数,则将其保留,然后转到len(L)-2。如果它为0,我们都不会这样做,这意味着pos=len(L)-1仍然存在,并且我们将永远反复查看该0。
所以,这是获得无限循环的一种方法。但是,我们假设它并没有以0结尾。
如果我们刚删除了一个负数,我们会回到elif,我们知道除非为0.否则为
但如果我们留下正数,那么我们现在有pos=len(L)-2,所以我们转到if。同样,pos=pos什么都不做。如果它是一个正数,我们将列表复制到自身,它什么都不做,然后设置pos=len(L)-2。它已经是同样的事情了。因此,如果倒数第二个数字是正数,那么我们将永远继续关注这个数字。这是获得无限循环的另一种方式。
如果是负面怎么办?然后L[:]=[L[pos]]+L[0:]会将您要删除的值添加到整个列表中(其中仍包含值的原始副本),L[:]=L[1:]会删除您刚刚添加的值,因此最终会得到相同的值你开始L。然后设置pos=len(L)-1,它返回到列表的末尾。我们知道它会成功运作,并再次回到倒数第二个位置,这仍然是相同的值,所以我们将永远来回穿梭。所以,这是获得无限循环的足够方式。
如果是0怎么办?然后我们什么也不做,所以pos和L永远不会改变,这是获得无限循环的另一种方式。
因此,一旦我们在列表的末尾得到一个肯定的元素,倒数第二个元素的所有三种可能性都是无限循环。
稍微退一步,您的代码设置pos的唯一内容是len(L)-1和len(L)-2。所以,即使你把所有其他东西都做对了,怎么可能在一个包含超过2个非负数的列表上完成呢?