Python remove element in for loop
[注意:即使使用临时数组(不修改循环数组),代码也没有给出列表EDOCX1[0]的正确答案。]
从列表中删除奇数,请参阅下面的代码。为什么它适用于list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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] |
你的问题源于这样一个事实:你没有像你想的那样循环浏览不同的列表。您希望避免在循环遍历列表时从列表中删除某些内容,这就是为什么您使用
但是,请注意,没有创建新列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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] |
。
最后请注意,当我将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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] |
1 2 3 4 5 6 7 8 9 | 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 |
。
在迭代列表时操作/删除元素会更改元素索引,
使用
运行以下函数有助于说明问题,请参阅3和4如何以某种方式处理运行程序:
1 2 3 4 5 6 7 8 9 | 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])) |
如果确实要使用列表组件修改原始对象:
1 2 3 | def purify(numbers): numbers[:] = [x for x in numbers if not x % 2] return numbers |
。
您也可以使用
1 2 3 4 5 | def purify(numbers): for item in reversed(numbers): if item % 2: numbers.remove(item) return numbers |
。
你做了两件你可能不应该做的事,因为他们都在自找麻烦。
在迭代数组时,永远不要添加或删除数组中的项。这将使Python和您都感到困惑,而且几乎肯定无法实现预期的结果。
无论如何,您确实不应该在适当的位置修改数组。函数没有得到数组的副本;它正在修改调用方传入的实际数组。这可能会让所有相关人员感到惊讶:
1 2 3 | a = [1,2,3,4] print purify(a) #=> [2, 4] print a #=> [2, 4] |
号
您应该构造并返回一个新的数组,并可能更改函数名以指示(类似于
1 2 3 4 5 6 | 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] |
这已经被问过很多次了,在迭代时查看修改列表
你真的应该这样做:
1 | even = [a for a in numbers if a%2 == 0] |
您的功能正以另一种您所期望的方式工作。for循环接受第一个元素,而不是第二个元素等,因此当您删除一个元素时,其他元素会更改它们的位置,当它们前面加上另一个奇数时,可以被它跳过(在您的情况下也会发生这种情况)。
您可以使用此代码:
1 2 | def purify(numbers): return [x for x in numbers if x % 2 == 0] |
。
它将分别返回A和B的[2,4][4,4]
如果要使用remove方法保留并返回相同的列表,可以尝试以下操作:
1 2 3 4 5 6 7 8 | 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 |