Python删除for循环中的元素

时间:2014-11-09 01:08:49

标签: python

[注意:即使使用临时数组(不修改循环数组),代码也没有为列表b提供正确的答案。]

从列表中删除奇数,请参阅下面的代码。 为什么它适用于列表a,而不是列表b?谢谢。

def purify(numbers):
    numbers_buf = numbers
    for item in numbers:
        if item % 2 == 1:
            numbers_buf.remove(item)
    return numbers_buf

a = [1,2,3,4]
print purify(a)
[2, 4]

b = [4,5,5,4]
print purify(b)
[4,5,4]

6 个答案:

答案 0 :(得分:1)

已多次询问此问题,请查看Modifying list while iterating

你真的应该这样做:

even = [a for a in numbers if a%2 == 0]

答案 1 :(得分:1)

你正在做两件你可能不应该做的事情,因为他们都在惹麻烦。

  1. 永远不会在迭代过程中添加或删除数组中的项目。这会让Python和你感到困惑,而且几乎肯定无法达到预期的效果。

  2. 无论如何,你真的不应该修改阵列。该函数没有得到数组的副本;它修改了调用者传入的实际数组。对于所有参与者来说,这可能是令人惊讶的行为:

    a = [1,2,3,4]
    print purify(a)        #=> [2, 4]
    print a                #=> [2, 4]
    
  3. 您应该构造并返回一个新数组,并且可能更改函数名称以指示(类似于sortsorted内置函数):

    def purified(a):
      return [n for n in a if n % 2 == 0]
    
    a = [1,2,3,4]
    print purified(a)      #=> [2, 4]
    print a                #=> [1, 2, 3, 4]
    

答案 2 :(得分:1)

numbers_buf = numbers[:] #  make a copy not a reference


def purify(numbers):
    numbers_buf = numbers[:]
    for item in numbers:
        if item % 2:
            numbers_buf.remove(item)
    return numbers_buf
迭代列表时操作/删除元素会改变元素的索引,numbers_buf = numbers创建对numbers列表的引用,基本上是指向同一个对象的指针,所以从一个删除,删除来自两者。

使用numbers[:]创建一个副本/新对象。

运行以下功能以帮助说清楚,看看3和4是如何做跑步者的:

def purify(numbers):
    numbers_buf = numbers
    should_be = numbers[:]
    for ind, item in enumerate(numbers):
        print("{} should be at {}, is at {}".format(item,should_be.index(item),ind))
        if item % 2:
            numbers_buf.remove(item)
    return numbers_buf
print(purify([4,5,4,7,3,1]))

如果您确实想使用list comp来修改原始对象:

def purify(numbers):
    numbers[:] = [x for x in numbers if not x % 2]
    return numbers

您还可以使用reversed

def purify(numbers):
    for item in reversed(numbers):
        if item % 2:
            numbers.remove(item)
    return numbers

答案 3 :(得分:1)

你的问题源于这样一个事实:你没有像你想要的那样循环遍历不同的列表。您希望避免在循环时从列表中删除某些内容,这就是您使用numbers_buf = numbers

创建新列表的原因

但请注意,未创建新列表:

In [73]: numbers = list(range(10))

In [74]: numbers
Out[74]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [75]: id(numbers)
Out[75]: 4469310792

In [76]: numbers_buf = numbers

In [77]: id(numbers)
Out[77]: 4469310792

In [78]: id(numbers_buf)
Out[78]: 4469310792

In [79]: id(numbers_buf) == id(numbers)
Out[79]: True

In [80]: numbers
Out[80]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [81]: numbers_buf
Out[81]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [82]: numbers.append(10)

In [83]: numbers_buf
Out[83]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

最后请注意,当我将10追加到numbers时,它也会附加到numbers_buf。这是因为当您执行numbers_buf = numbers时,python不会创建包含数字的新列表;它只是创建名称numbers_buf,并使其指向numbers指向的完全相同的结构(这就是所有id(numbers)内容所显示的内容)。您可以按如下方式解决此问题:

In [84]: numbers_buf_new = numbers[:]

In [85]: id(numbers_buf_new)
Out[85]: 4469329032

In [86]: id(numbers_buf_new) == id(numbers)
Out[86]: False

In [87]: numbers
Out[87]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [88]: numbers_buf_new
Out[88]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

In [89]: numbers.append(11)

In [90]: numbers
Out[90]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

In [91]: numbers_buf_new
Out[91]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

答案 4 :(得分:0)

如果你想保留使用remove方法并返回相同的列表,你可以试试这个:

def purify(numbers):

for item in numbers:
    if item % 2 == 1:
        count = numbers.count(item)
        for i in range(count):
            numbers.remove(item)
return numbers

答案 5 :(得分:0)

您的功能正在以您预期的方式工作。 for循环取第一个元素,而不是第二个元素,所以当你删除一个元素时,其他元素会改变它们的位置,并且当它们前面有另一个奇数时,可以跳过它(这种情况会发生在你的情况下)。

您可以改用此代码:

def purify(numbers):
return [x for x in numbers if x % 2 == 0]   

分别为a和b返回[2,4] [4,4]