list.remove(item)在Python中,它是如何工作的?

时间:2015-08-17 06:25:59

标签: python python-2.7

我想删除列表中的所有内容。但有些事让我很困惑...... 这是代码。     lst = [4,4,5,5]

for i in lst:
    if i % 2 == 0:
        print i
        lst.remove(i)

print lst

打印[4,5,5]为什么不[5,5]?

4 个答案:

答案 0 :(得分:2)

应该是这样的

for i in lst[:]:
    if i % 2 == 0:
        print i
        lst.remove(i)

print lst

<强>问题:

您在迭代时修改列表。由于迭代在完成之前停止了

<强>解决方案:

您可以迭代列表的副本

您可以使用list comprehension

lst=[i for i in lst if i%2 != 0]

答案 1 :(得分:2)

通过使用list.remove,您将在迭代期间修改列表。这会打破迭代,从而产生意想不到的结果。

一种解决方案是使用filter或列表推导创建新列表:

>>> filter(lambda i: i % 2 != 0, lst)
[5, 5]
>>> [i for i in lst if i % 2 != 0]
[5, 5]

如果需要,您可以将表达式分配给lst,但不能避免使用这些方法创建新的列表对象。

答案 2 :(得分:2)

其他答案已经提到您在迭代时修改列表,并提供了更好的方法。我个人更喜欢列表理解方法:

odd_numbers = [item for item in numbers if item % 2 != 0]

对于你指定的非常小的列表,我肯定会这样做。

但是,这会创建一个新列表,如果您有一个非常大的列表,这可能是一个问题。在整数的情况下,大可能至少意味着数百万,但确切地说,它需要开始给你带来内存使用问题。在这种情况下,有几种方法可以做到。

一种方法类似于问题中代码的意图。您遍历列表,删除偶数。但是,为了避免修改您正在迭代的列表导致的问题,您可以向后迭代向后。有一些方法可以向前迭代,但这更简单。

这是使用while循环的一种方式:

# A one hundred million item list that we don't want to copy
# even just the odd numbers from to put into a new list.
numbers = range(100000000)  # list(range(100000000)) in Python 3

index = len(numbers) - 1  # Start on the index of the last item
while index >= 0:
    if numbers[index] % 2 == 0:
        numbers.pop(index)
    index -= 1

以下是使用for循环的另一种方式:

# A one hundred million item list that we don't want to copy
# even just the odd numbers from to put into a new list.
numbers = range(100000000)  # list(range(100000000)) in Python 3

for index in xrange(len(numbers) - 1, -1, -1):  # range(...) in Python 3
    if numbers[index] % 2 == 0:
        numbers.pop(index)

请注意,在while循环和for循环版本中,我使用的是numbers.pop(index),而不是numbers.remove(numbers[index])。首先,.pop() 更高效,因为它提供了索引,而.remove()则必须在列表中搜索第一次出现的值。第二,注意我说,&#34;第一次出现的值&#34;。这意味着除非每个项目都是唯一的,否则使用.remove()会删除与循环当前所在项目不同的项目,最终会将当前项目留在列表中。

我还想提一个解决方案,因为您需要保留原始列表,但不想使用太多内存来存储奇数的副本。如果您只想迭代奇数一次(或者您反而使用内存,而不是在需要时重新计算内容),则可以使用生成器。这样做可以让您迭代列表中的奇数,而不需要任何额外的内存,除了生成器机制使用的无关紧要的数量。

生成器表达式的定义与列表推导完全相同,只是它括在括号中而不是方括号中:

odd_numbers = (item for item in numbers if item % 2 != 0)

请记住,生成器表达式是在原始列表上进行迭代,因此在迭代过程中更改原始列表会给您带来与在for循环中迭代列表时修改列表相同的问题。实际上,生成器表达式本身使用for循环。

顺便说一下,生成器表达式不应该只降级到非常大的列表;每当我不需要一次性计算整个列表时,我就会使用它们。

摘要/ TLDR:

&#34; best&#34;方式完全取决于你正在做什么,但这应该涵盖很多情况。

假设列表是&#34;小&#34;或&#34;大&#34;:

如果您的列表很小,请使用列表推导(如果可以,甚至使用生成器表达式)。如果它很大,请继续阅读。

如果您不需要原始列表,请使用while循环或for循环方法完全删除偶数(尽管使用.pop(),而不是{{1 }})。如果您确实需要原始列表,请继续阅读。

如果您只迭代奇数一次,请使用生成器表达式。如果您不止一次迭代它们,但是您愿意重复计算以节省内存,请使用生成器表达式。

如果你每次都要多次迭代奇数来重新计算它们,或者你需要随机访问,那么使用列表推导来创建一个只包含奇数的新列表。它会使用大量内存,但它们是休息时间。

答案 3 :(得分:1)

作为一般原则,您不应在迭代时修改集合。这导致跳过某些元素,并在某些情况下导致索引错误。

如果您只是创建具有相同名称的另一个引用,则不会从列表中删除元素,而是更容易。它的时间复杂度也较低。

lst = filter(lambda i: i % 2 !=0, lst)