如何在迭代时从列表中删除项目?

问题:如何在迭代时从列表中删除项目?

我正在遍历Python中的元组列表,并尝试在满足特定条件的情况下将其删除。

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

我应该用什么代替code_to_remove_tup?我不知道如何以这种方式删除项目。

I’m iterating over a list of tuples in Python, and am attempting to remove them if they meet certain criteria.

for tup in somelist:
    if determine(tup):
         code_to_remove_tup

What should I use in place of code_to_remove_tup? I can’t figure out how to remove the item in this fashion.


回答 0

您可以使用列表推导来创建一个仅包含您不想删除的元素的新列表:

somelist = [x for x in somelist if not determine(x)]

或者,通过分配给slice somelist[:],您可以将现有列表突变为仅包含所需的项目:

somelist[:] = [x for x in somelist if not determine(x)]

如果还有其他引用somelist需要反映更改,则此方法可能很有用。

除了理解之外,您还可以使用itertools。在Python 2中:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

或在Python 3中:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

为了清楚起见,以及对于那些发现使用[:]黑变或模糊表示法的人,这里有一个更明确的选择。从理论上讲,它在空间和时间上的表现应该与上面的单层表现相同。

temp = []
while somelist:
    x = somelist.pop()
    if not determine(x):
        temp.append(x)
while temp:
    somelist.append(templist.pop())

它也可以在其他语言中工作,而这些语言可能不具有Python列表的替换项功能,并且只需进行很少的修改即可。例如,并非所有语言都False像Python一样将空列表转换为。您可以替换while somelist:更明确的内容,例如while len(somelist) > 0:

You can use a list comprehension to create a new list containing only the elements you don’t want to remove:

somelist = [x for x in somelist if not determine(x)]

Or, by assigning to the slice somelist[:], you can mutate the existing list to contain only the items you want:

somelist[:] = [x for x in somelist if not determine(x)]

This approach could be useful if there are other references to somelist that need to reflect the changes.

Instead of a comprehension, you could also use itertools. In Python 2:

from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)

Or in Python 3:

from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)

For the sake of clarity and for those who find the use of the [:] notation hackish or fuzzy, here’s a more explicit alternative. Theoretically, it should perform the same with regards to space and time than the one-liners above.

temp = []
while somelist:
    x = somelist.pop()
    if not determine(x):
        temp.append(x)
while temp:
    somelist.append(templist.pop())

It also works in other languages that may not have the replace items ability of Python lists, with minimal modifications. For instance, not all languages cast empty lists to a False as Python does. You can substitute while somelist: for something more explicit like while len(somelist) > 0:.


回答 1

暗示列表理解的答案几乎是正确的-除了它们会建立一个全新的列表,然后为其命名与旧列表相同外,它们不会修改旧列表。这与@Lennart的建议中的选择性删除操作不同-速度更快,但是如果通过多个引用访问列表,则说明您只是在重新放置其中一个引用而不更改列表对象本身可能会导致微妙的灾难性错误。

幸运的是,获得列表理解的速度和就地变更所需的语义非常容易,只需编写代码即可:

somelist[:] = [tup for tup in somelist if determine(tup)]

请注意与其他答案的细微差别:这不是分配给裸名-而是分配给恰好是整个列表的列表切片,从而替换同一Python列表对象中的列表内容 ,而不仅仅是重新放置一个引用(从先前的列表对象到新的列表对象),就像其他答案一样。

The answers suggesting list comprehensions are ALMOST correct — except that they build a completely new list and then give it the same name the old list as, they do NOT modify the old list in place. That’s different from what you’d be doing by selective removal, as in @Lennart’s suggestion — it’s faster, but if your list is accessed via multiple references the fact that you’re just reseating one of the references and NOT altering the list object itself can lead to subtle, disastrous bugs.

Fortunately, it’s extremely easy to get both the speed of list comprehensions AND the required semantics of in-place alteration — just code:

somelist[:] = [tup for tup in somelist if determine(tup)]

Note the subtle difference with other answers: this one is NOT assigning to a barename – it’s assigning to a list slice that just happens to be the entire list, thereby replacing the list contents within the same Python list object, rather than just reseating one reference (from previous list object to new list object) like the other answers.


回答 2

您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,并可能导致意外结果。

例如(取决于列表的类型):

for tup in somelist[:]:
    etc....

一个例子:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]

You need to take a copy of the list and iterate over it first, or the iteration will fail with what may be unexpected results.

For example (depends on what type of list):

for tup in somelist[:]:
    etc....

An example:

>>> somelist = range(10)
>>> for x in somelist:
...     somelist.remove(x)
>>> somelist
[1, 3, 5, 7, 9]

>>> somelist = range(10)
>>> for x in somelist[:]:
...     somelist.remove(x)
>>> somelist
[]

回答 3

for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

您需要向后走,否则就像将您坐在的树枝锯掉一样:-)

Python 2用户:替换rangexrange以避免创建硬编码列表

for i in range(len(somelist) - 1, -1, -1):
    if some_condition(somelist, i):
        del somelist[i]

You need to go backwards otherwise it’s a bit like sawing off the tree-branch that you are sitting on :-)

Python 2 users: replace range by xrange to avoid creating a hardcoded list


回答 4

官方Python 2教程4.2。“用于声明”

https://docs.python.org/2/tutorial/controlflow.html#for-statements

这部分文档清楚地表明:

  • 您需要复制迭代列表以对其进行修改
  • 一种方法是使用切片符号 [:]

如果需要修改循环中要迭代的序列(例如,复制选定的项目),建议您首先进行复制。遍历序列不会隐式地创建副本。切片符号使这特别方便:

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

Python 2文档7.3。“ for声明”

https://docs.python.org/2/reference/compound_stmts.html#for

这部分文档再次说明您必须进行复制,并提供了一个实际的删除示例:

注意:循环修改序列时有一个微妙之处(这仅适用于可变序列,即列表)。内部计数器用于跟踪下一个要使用的项目,并且在每次迭代时都会递增。当该计数器达到序列的长度时,循环终止。这意味着,如果套件从序列中删除当前(或上一个)项目,则下一个项目将被跳过(因为它获取已被处理的当前项目的索引)。同样,如果套件在当前项目之前按顺序插入一个项目,则下次通过循环再次处理当前项目。这可能会导致讨厌的错误,可以通过使用整个序列的一部分进行临时复制来避免这些错误,例如,

for x in a[:]:
    if x < 0: a.remove(x)

但是,我不同意此实现,因为.remove()必须迭代整个列表以找到值。

最佳解决方法

要么:

通常.append(),除非内存是一个大问题,否则默认情况下,您只想使用默认选项。

Python可以做得更好吗?

似乎可以改进此特定的Python API。例如,将其与:

两者都清楚地表明,除了使用迭代器本身之外,您无法修改要迭代的列表,并为您提供了无需复制列表即可进行修改的有效方法。

可能的基本原理是,假定Python列表是由动态数组支持的,因此,任何类型的删除都将在时间上效率低下,而Java具有更好的接口层次结构,同时包含ArrayListLinkedList实现ListIterator

Python stdlib中似乎也没有明确的链接列表类型:Python链接列表

Official Python 2 tutorial 4.2. “for Statements”

https://docs.python.org/2/tutorial/controlflow.html#for-statements

This part of the docs makes it clear that:

  • you need to make a copy of the iterated list to modify it
  • one way to do it is with the slice notation [:]

If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy. Iterating over a sequence does not implicitly make a copy. The slice notation makes this especially convenient:

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']

Python 2 documentation 7.3. “The for statement”

https://docs.python.org/2/reference/compound_stmts.html#for

This part of the docs says once again that you have to make a copy, and gives an actual removal example:

Note: There is a subtlety when the sequence is being modified by the loop (this can only occur for mutable sequences, i.e. lists). An internal counter is used to keep track of which item is used next, and this is incremented on each iteration. When this counter has reached the length of the sequence the loop terminates. This means that if the suite deletes the current (or a previous) item from the sequence, the next item will be skipped (since it gets the index of the current item which has already been treated). Likewise, if the suite inserts an item in the sequence before the current item, the current item will be treated again the next time through the loop. This can lead to nasty bugs that can be avoided by making a temporary copy using a slice of the whole sequence, e.g.,

for x in a[:]:
    if x < 0: a.remove(x)

However, I disagree with this implementation, since .remove() has to iterate the entire list to find the value.

Best workarounds

Either:

Generally you just want to go for the faster .append() option by default unless memory is a big concern.

Could Python do this better?

It seems like this particular Python API could be improved. Compare it, for instance, with:

  • Java ListIterator::remove which documents “This call can only be made once per call to next or previous”
  • C++ std::vector::erase which returns a valid interator to the element after the one removed

both of which make it crystal clear that you cannot modify a list being iterated except with the iterator itself, and gives you efficient ways to do so without copying the list.

Perhaps the underlying rationale is that Python lists are assumed to be dynamic array backed, and therefore any type of removal will be time inefficient anyways, while Java has a nicer interface hierarchy with both ArrayList and LinkedList implementations of ListIterator.

There doesn’t seem to be an explicit linked list type in the Python stdlib either: Python Linked List


回答 5

此类示例的最佳方法是列表理解

somelist = [tup for tup in somelist if determine(tup)]

如果您要做的事情比调用determine函数更复杂,我更喜欢构造一个新列表,然后随便添加一个新列表。例如

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

使用列表复制列表remove可能会使您的代码看起来更简洁,如以下答案之一所述。您绝对不应该对非常大的列表执行此操作,因为这涉及到首先复制整个列表,然后O(n) remove对要删除的每个元素执行操作,从而使其成为一种O(n^2)算法。

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

Your best approach for such an example would be a list comprehension

somelist = [tup for tup in somelist if determine(tup)]

In cases where you’re doing something more complex than calling a determine function, I prefer constructing a new list and simply appending to it as I go. For example

newlist = []
for tup in somelist:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)
somelist = newlist

Copying the list using remove might make your code look a little cleaner, as described in one of the answers below. You should definitely not do this for extremely large lists, since this involves first copying the entire list, and also performing an O(n) remove operation for each element being removed, making this an O(n^2) algorithm.

for tup in somelist[:]:
    # lots of code here, possibly setting things up for calling determine
    if determine(tup):
        newlist.append(tup)

回答 6

对于那些喜欢函数式编程的人:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

要么

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

For those that like functional programming:

somelist[:] = filter(lambda tup: not determine(tup), somelist)

or

from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))

回答 7

我需要使用大量列表来完成此操作,并且复制列表似乎很昂贵,尤其是因为在我的情况下,与保留的项目相比,删除的数量很少。我采用了这种低级方法。

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

我不知道相对于复制大型列表而言,几次删除的效率如何。如果您有任何见解,请发表评论。

I needed to do this with a huge list, and duplicating the list seemed expensive, especially since in my case the number of deletions would be few compared to the items that remain. I took this low-level approach.

array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
    if someTest(array[i]):
        del array[i]
        arraySize -= 1
    else:
        i += 1

What I don’t know is how efficient a couple of deletes are compared to copying a large list. Please comment if you have any insight.


回答 8

如果当前列表项符合期望的条件,则仅创建一个新列表也可能很聪明。

所以:

for item in originalList:
   if (item != badValue):
        newList.append(item)

并且避免必须使用新的列表名称重新编码整个项目:

originalList[:] = newList

注意,来自Python文档:

copy.copy(x)返回x的浅表副本。

copy.deepcopy(x)返回x的深层副本。

It might be smart to also just create a new list if the current list item meets the desired criteria.

so:

for item in originalList:
   if (item != badValue):
        newList.append(item)

and to avoid having to re-code the entire project with the new lists name:

originalList[:] = newList

note, from Python documentation:

copy.copy(x) Return a shallow copy of x.

copy.deepcopy(x) Return a deep copy of x.


回答 9

此答案最初是为回答一个问题而编写的,此问题已被标记为重复: 从python列表中删除坐标

您的代码中有两个问题:

1)使用remove()时,您尝试删除整数,而您需要删除元组。

2)for循环将跳过列表中的项目。

让我们看一下执行代码时发生的情况:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

第一个问题是您要将’a’和’b’都传递给remove(),但是remove()仅接受单个参数。那么,如何才能使remove()与您的列表一起正常工作?我们需要弄清楚列表中的每个元素是什么。在这种情况下,每个都是一个元组。要看到这一点,让我们访问列表的一个元素(索引从0开始):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

啊哈!L1的每个元素实际上都是一个元组。这就是我们需要传递给remove()的东西。python中的元组非常简单,只需将值括在括号中即可。“ a,b”不是元组,但是“(a,b)”是元组。因此,我们修改您的代码并再次运行:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

这段代码运行无误,但让我们看一下它输出的列表:

L1 is now: [(1, 2), (5, 6), (1, -2)]

为什么(1,-2)仍在您的列表中?事实证明,在使用循环迭代列表时修改列表是一个非常糟糕的主意,无需特别注意。(1,-2)保留在列表中的原因是列表中每个项目的位置在for循环的迭代之间更改。让我们看看如果将上面的代码提供给更长的列表会发生什么:

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

从该结果可以推断,每次条件语句的值为true且列表项被删除时,循环的下一次迭代将跳过对列表中下一项的评估,因为其值现在位于不同的索引处。

最直观的解决方案是复制列表,然后遍历原始列表并仅修改副本。您可以尝试这样做:

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

但是,输出将与之前相同:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

这是因为当我们创建L2时,python实际上并未创建新对象。相反,它仅将L2引用为与L1相同的对象。我们可以使用“ is”来验证这一点,而“ is”不同于“等于”(==)。

>>> L2=L1
>>> L1 is L2
True

我们可以使用copy.copy()制作一个真实的副本。然后一切都按预期工作:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

最后,有一个更清洁的解决方案,而不是必须制作全新的L1副本。reversed()函数:

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

不幸的是,我无法充分描述reversed()的工作方式。当列表传递给它时,它返回一个“ listreverseiterator”对象。出于实际目的,您可以将其视为创建其参数的反向副本。这是我推荐的解决方案。

This answer was originally written in response to a question which has since been marked as duplicate: Removing coordinates from list on python

There are two problems in your code:

1) When using remove(), you attempt to remove integers whereas you need to remove a tuple.

2) The for loop will skip items in your list.

Let’s run through what happens when we execute your code:

>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
...   if a < 0 or b < 0:
...     L1.remove(a,b)
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)

The first problem is that you are passing both ‘a’ and ‘b’ to remove(), but remove() only accepts a single argument. So how can we get remove() to work properly with your list? We need to figure out what each element of your list is. In this case, each one is a tuple. To see this, let’s access one element of the list (indexing starts at 0):

>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>

Aha! Each element of L1 is actually a tuple. So that’s what we need to be passing to remove(). Tuples in python are very easy, they’re simply made by enclosing values in parentheses. “a, b” is not a tuple, but “(a, b)” is a tuple. So we modify your code and run it again:

# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))

This code runs without any error, but let’s look at the list it outputs:

L1 is now: [(1, 2), (5, 6), (1, -2)]

Why is (1,-2) still in your list? It turns out modifying the list while using a loop to iterate over it is a very bad idea without special care. The reason that (1, -2) remains in the list is that the locations of each item within the list changed between iterations of the for loop. Let’s look at what happens if we feed the above code a longer list:

L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

As you can infer from that result, every time that the conditional statement evaluates to true and a list item is removed, the next iteration of the loop will skip evaluation of the next item in the list because its values are now located at different indices.

The most intuitive solution is to copy the list, then iterate over the original list and only modify the copy. You can try doing so like this:

L2 = L1
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)

However, the output will be identical to before:

'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]

This is because when we created L2, python did not actually create a new object. Instead, it merely referenced L2 to the same object as L1. We can verify this with ‘is’ which is different from merely “equals” (==).

>>> L2=L1
>>> L1 is L2
True

We can make a true copy using copy.copy(). Then everything works as expected:

import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
    if a < 0 or b < 0 :
        L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Finally, there is one cleaner solution than having to make an entirely new copy of L1. The reversed() function:

L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
    if a < 0 or b < 0 :
        L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]

Unfortunately, I cannot adequately describe how reversed() works. It returns a ‘listreverseiterator’ object when a list is passed to it. For practical purposes, you can think of it as creating a reversed copy of its argument. This is the solution I recommend.


回答 10

如果要在迭代过程中执行其他任何操作,最好同时获得索引(这可以保证您能够引用它,例如,如果您有字典列表)和实际的列表项内容。

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

enumerate使您可以立即访问项目和索引。reversed这样一来,您以后要删除的索引就不会改变。

If you want to do anything else during the iteration, it may be nice to get both the index (which guarantees you being able to reference it, for example if you have a list of dicts) and the actual list item contents.

inlist = [{'field1':10, 'field2':20}, {'field1':30, 'field2':15}]    
for idx, i in enumerate(inlist):
    do some stuff with i['field1']
    if somecondition:
        xlist.append(idx)
for i in reversed(xlist): del inlist[i]

enumerate gives you access to the item and the index at once. reversed is so that the indices that you’re going to later delete don’t change on you.


回答 11

您可能要使用filter()available作为内置函数。

欲了解更多详情,请点击这里

You might want to use filter() available as the built-in.

For more details check here


回答 12

这里的大多数答案都希望您创建列表的副本。我有一个用例,其中的列表很长(110K个项),而继续缩小列表会更明智。

首先,您需要将while循环替换为foreach循环

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

i在if块中,不会更改的值,因为一旦删除了旧项,您将希望从相同的索引中获取新项的值。

Most of the answers here want you to create a copy of the list. I had a use case where the list was quite long (110K items) and it was smarter to keep reducing the list instead.

First of all you’ll need to replace foreach loop with while loop,

i = 0
while i < len(somelist):
    if determine(somelist[i]):
         del somelist[i]
    else:
        i += 1

The value of i is not changed in the if block because you’ll want to get value of the new item FROM THE SAME INDEX, once the old item is deleted.


回答 13

您可以尝试反向进行循环,因此对于some_list,您将执行以下操作:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

这样,索引是对齐的,并且不会受到列表更新的影响(无论是否弹出cur元素)。

You can try for-looping in reverse so for some_list you’ll do something like:

list_len = len(some_list)
for i in range(list_len):
    reverse_i = list_len - 1 - i
    cur = some_list[reverse_i]

    # some logic with cur element

    if some_condition:
        some_list.pop(reverse_i)

This way the index is aligned and doesn’t suffer from the list updates (regardless whether you pop cur element or not).


回答 14

一种可能的解决方案,如果您不仅要删除某些内容,而且还希望在单个循环中对所有元素执行某些操作,则很有用:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

One possible solution, useful if you want not only remove some things, but also do something with all elements in a single loop:

alist = ['good', 'bad', 'good', 'bad', 'good']
i = 0
for x in alist[:]:
    if x == 'bad':
        alist.pop(i)
        i -= 1
    # do something cool with x or just print x
    print(x)
    i += 1

回答 15

我需要做类似的事情,在我的情况下,问题是内存-我需要将列表中的多个数据集对象合并,然后再对它们做一些事情,作为一个新对象,并且需要摆脱要合并的每个条目避免重复所有操作并浪费内存。就我而言,将对象放在字典中而不是列表中可以很好地工作:

“`

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

“`

I needed to do something similar and in my case the problem was memory – I needed to merge multiple dataset objects within a list, after doing some stuff with them, as a new object, and needed to get rid of each entry I was merging to avoid duplicating all of them and blowing up memory. In my case having the objects in a dictionary instead of a list worked fine:

“`

k = range(5)
v = ['a','b','c','d','e']
d = {key:val for key,val in zip(k, v)}

print d
for i in range(5):
    print d[i]
    d.pop(i)
print d

“`


回答 16

TLDR:

我写了一个库,使您可以执行此操作:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

如果可能的话,最好使用另一种方法,该方法不需要在迭代时修改可迭代对象,但是对于某些算法,可能不是那么简单。因此,如果您确定确实希望原始问题中描述的代码模式,则可以。

应该适用于所有可变序列,而不仅仅是列表。


完整答案:

编辑:此答案中的最后一个代码示例给出了一个用例,说明了为什么有时您可能想在适当位置修改列表而不是使用列表理解。答案的第一部分用作如何在适当位置修改数组的教程。

从senderle的答案(针对相关问题)可以得出解决方案。这说明了在遍历已修改的列表时如何更新数组索引。即使解决方案列表被修改,下面的解决方案旨在正确跟踪数组索引。

fluidIter.py这里 下载https://github.com/alanbacon/FluidIterator,它只是一个文件,因此无需安装git。没有安装程序,因此您需要确保该文件位于您自己的python路径中。该代码是为python 3编写的,未经python 2的测试。

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

这将产生以下输出:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

上面我们pop在流体列表对象上使用了该方法。其他常见的迭代方法也实现,诸如del fluidL[i].remove.insert.append.extend。还可以使用切片修改列表(sort并且reverse未实现方法)。

唯一的条件是,您必须仅在适当位置修改列表,如果在任何时候fluidL或将l其重新分配给其他列表对象,代码将无法工作。原始fluidL对象仍将由for循环使用,但超出范围供我们修改。

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

如果要访问列表的当前索引值,则不能使用枚举,因为它仅计算for循环已运行了多少次。相反,我们将直接使用迭代器对象。

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

这将输出以下内容:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

FluidIterable类只是提供了原始列表对象的包装。可以将原始对象作为流体对象的属性进行访问,如下所示:

originalList = fluidArr.fixedIterable

可以if __name__ is "__main__":在底部的部分找到更多示例/测试fluidIter.py。这些值得一看,因为它们解释了在各种情况下会发生什么。例如:使用切片替换列表的大部分。或在嵌套for循环中使用(并修改)相同的可迭代对象。

就像我刚开始所说的那样:这是一个复杂的解决方案,将损害代码的可读性,并使调试更加困难。因此,应该首先考虑其他解决方案,例如David Raznick的答案中提到的列表理解。话虽如此,但我发现此类对我有用并且比跟踪需要删除的元素的索引更容易使用的时代。


编辑:如评论中所述,此答案并未真正提出此方法可提供解决方案的问题。我将在这里尝试解决:

列表理解提供了一种生成新列表的方法,但是这些方法倾向于孤立地查看每个元素,而不是整个列表的当前状态。

newList = [i for i in oldList if testFunc(i)]

但是,如果的结果testFunc取决于已添加的元素newList怎么办?还是仍然oldList可以添加其中的元素?也许仍然可以使用列表理解的方法,但是它会开始失去它的优雅感,对我来说,修改列表很容易。

下面的代码是遭受上述问题的一种算法示例。该算法将减少列表,以使任何元素都不是其他任何元素的倍数。

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

输出和最终的简化列表如下所示

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

TLDR:

I wrote a library that allows you to do this:

from fluidIter import FluidIterable
fSomeList = FluidIterable(someList)  
for tup in fSomeList:
    if determine(tup):
        # remove 'tup' without "breaking" the iteration
        fSomeList.remove(tup)
        # tup has also been removed from 'someList'
        # as well as 'fSomeList'

It’s best to use another method if possible that doesn’t require modifying your iterable while iterating over it, but for some algorithms it might not be that straight forward. And so if you are sure that you really do want the code pattern described in the original question, it is possible.

Should work on all mutable sequences not just lists.


Full answer:

Edit: The last code example in this answer gives a use case for why you might sometimes want to modify a list in place rather than use a list comprehension. The first part of the answers serves as tutorial of how an array can be modified in place.

The solution follows on from this answer (for a related question) from senderle. Which explains how the the array index is updated while iterating through a list that has been modified. The solution below is designed to correctly track the array index even if the list is modified.

Download fluidIter.py from here https://github.com/alanbacon/FluidIterator, it is just a single file so no need to install git. There is no installer so you will need to make sure that the file is in the python path your self. The code has been written for python 3 and is untested on python 2.

from fluidIter import FluidIterable
l = [0,1,2,3,4,5,6,7,8]  
fluidL = FluidIterable(l)                       
for i in fluidL:
    print('initial state of list on this iteration: ' + str(fluidL)) 
    print('current iteration value: ' + str(i))
    print('popped value: ' + str(fluidL.pop(2)))
    print(' ')

print('Final List Value: ' + str(l))

This will produce the following output:

initial state of list on this iteration: [0, 1, 2, 3, 4, 5, 6, 7, 8]
current iteration value: 0
popped value: 2

initial state of list on this iteration: [0, 1, 3, 4, 5, 6, 7, 8]
current iteration value: 1
popped value: 3

initial state of list on this iteration: [0, 1, 4, 5, 6, 7, 8]
current iteration value: 4
popped value: 4

initial state of list on this iteration: [0, 1, 5, 6, 7, 8]
current iteration value: 5
popped value: 5

initial state of list on this iteration: [0, 1, 6, 7, 8]
current iteration value: 6
popped value: 6

initial state of list on this iteration: [0, 1, 7, 8]
current iteration value: 7
popped value: 7

initial state of list on this iteration: [0, 1, 8]
current iteration value: 8
popped value: 8

Final List Value: [0, 1]

Above we have used the pop method on the fluid list object. Other common iterable methods are also implemented such as del fluidL[i], .remove, .insert, .append, .extend. The list can also be modified using slices (sort and reverse methods are not implemented).

The only condition is that you must only modify the list in place, if at any point fluidL or l were reassigned to a different list object the code would not work. The original fluidL object would still be used by the for loop but would become out of scope for us to modify.

i.e.

fluidL[2] = 'a'   # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8]  # is not OK

If we want to access the current index value of the list we cannot use enumerate, as this only counts how many times the for loop has run. Instead we will use the iterator object directly.

fluidArr = FluidIterable([0,1,2,3])
# get iterator first so can query the current index
fluidArrIter = fluidArr.__iter__()
for i, v in enumerate(fluidArrIter):
    print('enum: ', i)
    print('current val: ', v)
    print('current ind: ', fluidArrIter.currentIndex)
    print(fluidArr)
    fluidArr.insert(0,'a')
    print(' ')

print('Final List Value: ' + str(fluidArr))

This will output the following:

enum:  0
current val:  0
current ind:  0
[0, 1, 2, 3]

enum:  1
current val:  1
current ind:  2
['a', 0, 1, 2, 3]

enum:  2
current val:  2
current ind:  4
['a', 'a', 0, 1, 2, 3]

enum:  3
current val:  3
current ind:  6
['a', 'a', 'a', 0, 1, 2, 3]

Final List Value: ['a', 'a', 'a', 'a', 0, 1, 2, 3]

The FluidIterable class just provides a wrapper for the original list object. The original object can be accessed as a property of the fluid object like so:

originalList = fluidArr.fixedIterable

More examples / tests can be found in the if __name__ is "__main__": section at the bottom of fluidIter.py. These are worth looking at because they explain what happens in various situations. Such as: Replacing a large sections of the list using a slice. Or using (and modifying) the same iterable in nested for loops.

As I stated to start with: this is a complicated solution that will hurt the readability of your code and make it more difficult to debug. Therefore other solutions such as the list comprehensions mentioned in David Raznick’s answer should be considered first. That being said, I have found times where this class has been useful to me and has been easier to use than keeping track of the indices of elements that need deleting.


Edit: As mentioned in the comments, this answer does not really present a problem for which this approach provides a solution. I will try to address that here:

List comprehensions provide a way to generate a new list but these approaches tend to look at each element in isolation rather than the current state of the list as a whole.

i.e.

newList = [i for i in oldList if testFunc(i)]

But what if the result of the testFunc depends on the elements that have been added to newList already? Or the elements still in oldList that might be added next? There might still be a way to use a list comprehension but it will begin to lose it’s elegance, and for me it feels easier to modify a list in place.

The code below is one example of an algorithm that suffers from the above problem. The algorithm will reduce a list so that no element is a multiple of any other element.

randInts = [70, 20, 61, 80, 54, 18, 7, 18, 55, 9]
fRandInts = FluidIterable(randInts)
fRandIntsIter = fRandInts.__iter__()
# for each value in the list (outer loop)
# test against every other value in the list (inner loop)
for i in fRandIntsIter:
    print(' ')
    print('outer val: ', i)
    innerIntsIter = fRandInts.__iter__()
    for j in innerIntsIter:
        innerIndex = innerIntsIter.currentIndex
        # skip the element that the outloop is currently on
        # because we don't want to test a value against itself
        if not innerIndex == fRandIntsIter.currentIndex:
            # if the test element, j, is a multiple 
            # of the reference element, i, then remove 'j'
            if j%i == 0:
                print('remove val: ', j)
                # remove element in place, without breaking the
                # iteration of either loop
                del fRandInts[innerIndex]
            # end if multiple, then remove
        # end if not the same value as outer loop
    # end inner loop
# end outerloop

print('')
print('final list: ', randInts)

The output and the final reduced list are shown below

outer val:  70

outer val:  20
remove val:  80

outer val:  61

outer val:  54

outer val:  18
remove val:  54
remove val:  18

outer val:  7
remove val:  70

outer val:  55

outer val:  9
remove val:  18

final list:  [20, 61, 7, 55, 9]

回答 17

最有效的方法是列表理解,很多人都表现出他们的情况,当然,这也是一个很好的方式得到一个iterator通过filter

Filter接收一个函数和一个序列。Filter将传递的函数依次应用于每个元素,然后根据函数返回值是True还是决定是保留还是丢弃该元素False

有一个例子(在元组中获得赔率):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

警告:您也不能处理迭代器。迭代器有时比序列更好。

The most effective method is list comprehension, many people show their case, of course, it is also a good way to get an iterator through filter.

Filter receives a function and a sequence. Filter applies the passed function to each element in turn, and then decides whether to retain or discard the element depending on whether the function return value is True or False.

There is an example (get the odds in the tuple):

list(filter(lambda x:x%2==1, (1, 2, 4, 5, 6, 9, 10, 15)))  
# result: [1, 5, 9, 15]

Caution: You can also not handle iterators. Iterators are sometimes better than sequences.


回答 18

for循环将通过索引进行迭代。

认为你有一个清单,

[5, 7, 13, 29, 65, 91]

您使用了名为的列表变量lis。并且您使用它删除。

你的变量

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

在第5次迭代中

您的数字35不是素数,因此您将其从列表中删除。

lis.remove(y)

然后下一个值(65)移至上一个索引。

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

所以第4次迭代完成的指针移到了第5位。

那就是为什么您的循环自从移入上一个索引以来不覆盖65。

因此,您不应将列表引用到另一个仍引用原始变量而不是副本的变量中。

ite = lis #dont do it will reference instead copy

所以使用 list[::]

现在你会给,

[5, 7, 13, 29]

问题是您在迭代过程中从列表中删除了一个值,然后列表索引将崩溃。

因此您可以尝试理解。

它支持所有可迭代的对象,例如list,tuple,dict,string等

for loop will be iterate through index..

consider you have a list,

[5, 7, 13, 29, 65, 91]

you have using list variable called lis. and you using same to remove..

your variable

lis = [5, 7, 13, 29, 35, 65, 91]
       0  1   2   3   4   5   6

during 5th iteration,

your number 35 was not a prime so you removed it from a list.

lis.remove(y)

and then next value (65) move on to previous index.

lis = [5, 7, 13, 29, 65, 91]
       0  1   2   3   4   5

so 4th iteration done pointer moved onto 5th..

thats why your loop doesnt cover 65 since its moved into previous index.

so you shouldn’t reference list into another variable which still reference original instead of copy.

ite = lis #dont do it will reference instead copy

so do copy of list using list[::]

now you it will give,

[5, 7, 13, 29]

Problem is you removed a value from a list during iteration then your list index will collapse.

so you can try comprehension instead.

which supports all the iterable like, list, tuple, dict, string etc


回答 19

如果要在迭代时从列表中删除元素,请使用while循环,以便可以在每次删除后更改当前索引和结束索引。

例:

i = 0
length = len(list1)

while i < length:
    if condition:
        list1.remove(list1[i])
        i -= 1
        length -= 1

    i += 1

If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.

Example:

i = 0
length = len(list1)

while i < length:
    if condition:
        list1.remove(list1[i])
        i -= 1
        length -= 1

    i += 1

回答 20

其他答案是正确的,因为从要迭代的列表中删除通常不是一个好主意。反向迭代避免了陷阱,但是遵循这样做的代码要困难得多,因此通常最好使用列表推导或filter

但是,在一种情况下,可以安全地从要迭代的序列中删除元素:如果仅在迭代时删除一个项目。可以使用a return或a 来确保break。例如:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

当您对符合条件的列表中的第一个项目执行副作用操作,然后立即从列表中删除该项目时,这通常比列表理解更容易理解。

The other answers are correct that it is usually a bad idea to delete from a list that you’re iterating. Reverse iterating avoids the pitfalls, but it is much more difficult to follow code that does that, so usually you’re better off using a list comprehension or filter.

There is, however, one case where it is safe to remove elements from a sequence that you are iterating: if you’re only removing one item while you’re iterating. This can be ensured using a return or a break. For example:

for i, item in enumerate(lst):
    if item % 4 == 0:
        foo(item)
        del lst[i]
        break

This is often easier to understand than a list comprehension when you’re doing some operations with side effects on the first item in a list that meets some condition and then removing that item from the list immediately after.


回答 21

我可以想到三种解决问题的方法。例如,我将创建一个随机的元组列表somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]。我选择的条件是sum of elements of a tuple = 15。在最终列表中,我们将只有那些总和不等于15的元组。

我选择的是一个随机选择的示例。可以随意更改元组的列表条件,我选择了。

方法1.>使用您建议的框架(其中一个在for循环内填写代码)。我使用一个小的代码del来删除满足上述条件的元组。但是,如果两个连续放置的元组满足给定条件,则此方法将丢失一个元组(满足所述条件)。

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

方法2.>构造一个新列表,其中包含不满足给定条件的元素(元组)(这与删除满足给定条件的list的元素相同)。以下是该代码:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

方法3.>查找满足给定条件的索引,然后使用与这些索引相对应的remove元素(元组)。以下是该代码。

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

方法1和方法2比方法3快。方法2和方法3比方法1更有效。我更喜欢method2。对于上述示例,time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

I can think of three approaches to solve your problem. As an example, I will create a random list of tuples somelist = [(1,2,3), (4,5,6), (3,6,6), (7,8,9), (15,0,0), (10,11,12)]. The condition that I choose is sum of elements of a tuple = 15. In the final list we will only have those tuples whose sum is not equal to 15.

What I have chosen is a randomly chosen example. Feel free to change the list of tuples and the condition that I have chosen.

Method 1.> Use the framework that you had suggested (where one fills in a code inside a for loop). I use a small code with del to delete a tuple that meets the said condition. However, this method will miss a tuple (which satisfies the said condition) if two consecutively placed tuples meet the given condition.

for tup in somelist:
    if ( sum(tup)==15 ): 
        del somelist[somelist.index(tup)]

print somelist
>>> [(1, 2, 3), (3, 6, 6), (7, 8, 9), (10, 11, 12)]

Method 2.> Construct a new list which contains elements (tuples) where the given condition is not met (this is the same thing as removing elements of list where the given condition is met). Following is the code for that:

newlist1 = [somelist[tup] for tup in range(len(somelist)) if(sum(somelist[tup])!=15)]

print newlist1
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Method 3.> Find indices where the given condition is met, and then use remove elements (tuples) corresponding to those indices. Following is the code for that.

indices = [i for i in range(len(somelist)) if(sum(somelist[i])==15)]
newlist2 = [tup for j, tup in enumerate(somelist) if j not in indices]

print newlist2
>>>[(1, 2, 3), (7, 8, 9), (10, 11, 12)]

Method 1 and method 2 are faster than method 3. Method2 and method3 are more efficient than method1. I prefer method2. For the aforementioned example, time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7


回答 22

对于具有很大潜力的任何事物,我使用以下内容。

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

那应该比其他任何东西都快得多。

For anything that has the potential to be really big, I use the following.

import numpy as np

orig_list = np.array([1, 2, 3, 4, 5, 100, 8, 13])

remove_me = [100, 1]

cleaned = np.delete(orig_list, remove_me)
print(cleaned)

That should be significantly faster than anything else.


回答 23

在某些情况下,您要做的不仅仅是一次过滤一个列表,还希望迭代时更改迭代。

这是一个示例,其中事先复制列表是不正确的,不可能进行反向迭代,并且列表理解也不是一种选择。

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

In some situations, where you’re doing more than simply filtering a list one item at time, you want your iteration to change while iterating.

Here is an example where copying the list beforehand is incorrect, reverse iteration is impossible and a list comprehension is also not an option.

""" Sieve of Eratosthenes """

def generate_primes(n):
    """ Generates all primes less than n. """
    primes = list(range(2,n))
    idx = 0
    while idx < len(primes):
        p = primes[idx]
        for multiple in range(p+p, n, p):
            try:
                primes.remove(multiple)
            except ValueError:
                pass #EAFP
        idx += 1
        yield p

回答 24

如果以后要使用新列表,只需将elem设置为None,然后在以后的循环中进行判断,就像这样

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

这样,您无需复制列表,而且更容易理解。

If you will use the new list later, you can simply set the elem to None, and then judge it in the later loop, like this

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

In this way, you dont’t need copy the list and it’s easier to understand.


回答 25

提出一个数字列表,您想删除所有可被3整除的数字,

list_number =[i for i in range(100)]

使用list comprehension,这将创建一个新列表并创建新的内存空间

new_list =[i for i in list_number if i%3!=0]

使用lambda filter函数,这将创建结果新列表并占用内存空间

new_list = list(filter(lambda x:x%3!=0, list_number))

无需占用新列表和修改现有列表的存储空间

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)

uppose a list of number and you want to remove all no which are divisible by 3,

list_number =[i for i in range(100)]

using list comprehension,this will careate a new list and create new memory space

new_list =[i for i in list_number if i%3!=0]

using lambda filter function, this will create resultant new list and consume memeory space

new_list = list(filter(lambda x:x%3!=0, list_number))

without consuming memory space for new list and modify existing list

for index, value in enumerate(list_number):
    if list_number[index]%3==0:
        list_number.remove(value)