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

时间:2009-07-30 15:36:42

标签: python iteration

我正在迭代Python中的元组列表,并且如果它们符合某些条件,我会尝试删除它们。

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

我应该使用什么代替code_to_remove_tup?我无法弄清楚如何以这种方式删除项目。

30 个答案:

答案 0 :(得分:714)

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

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

或者,通过分配切片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)

答案 1 :(得分:532)

建议列表推导的答案几乎是正确的 - 除了它们构建一个全新的列表然后给它与旧列表相同的名称,它们不会修改旧的列表。这与你通过选择性删除所做的不同,如在@Lennart's suggestion中 - 它更快,但如果你的列表是通过多个引用访问的,那么你只是重新安装其中一个引用并且不改变它list对象本身可能导致细微的,灾难性的错误。

幸运的是,获得列表推导的速度和就地更改所需的语义非常容易 - 只需代码:

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

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

答案 2 :(得分:238)

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

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

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
[]

答案 3 :(得分:105)

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

你需要倒退,否则就像锯掉你所坐的树枝一样: - )

Python 2用户:将range替换为xrange以避免创建硬编码列表

答案 4 :(得分:46)

这样一个例子的最佳方法是list comprehension

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)

答案 5 :(得分:42)

官方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。例如,将它与Java对应ListIterator进行比较,这清楚地表明除了迭代器本身之外你不能修改正在迭代的列表,并且在不复制列表的情况下为你提供了有效的方法。

也许基本的理由是假设Python列表是动态数组支持的,因此任何类型的删除都是时间效率低的,而Java有一个更好的接口层次结构ArrayList和{{3} } ListIterator

的实现

在Python stdlib中似乎没有显式链接列表类型:LinkedList

答案 6 :(得分:36)

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

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

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

答案 7 :(得分:10)

我需要用一个巨大的列表来执行此操作,并且复制列表似乎很昂贵,特别是因为在我的情况下,删除的数量与剩余的项目相比很少。我采用了这种低级别的方法。

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

我不知道的是,将几个删除与复制大型列表相比有多高效。如果您有任何见解,请发表评论。

答案 8 :(得分:10)

如果当前列表项符合所需条件,也可以创建新列表。

这样:

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

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

originalList[:] = newList

请注意,来自Python文档:

  

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

     

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

答案 9 :(得分:8)

这个答案最初是针对一个被标记为重复的问题而写的: Removing coordinates from list on 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)

第一个问题是你正在通过两个&#39; a&#39;和&#39; b&#39;删除(),但remove()只接受一个参数。那么我们怎样才能让remove()与你的列表一起正常工作呢?我们需要弄清楚列表中每个元素是什么。在这种情况下,每个都是一个元组。要看到这一点,让我们访问列表中的一个元素(索引从0开始):

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

啊哈! L1的每个元素实际上都是一个元组。这就是我们需要传递给remove()的东西。 python中的元组非常简单,它们只是通过将值括在括号中来制作。 &#34; a,b&#34;不是一个元组,而是&#34;(a,b)&#34;是一个元组。因此,我们修改您的代码并再次运行:

# 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相同的对象。我们可以通过&#39;来验证这一点。这不仅仅是&#34;等于&#34; (==)。

>>> 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副本。 reverse()函数:

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)]

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

答案 10 :(得分:4)

如果你想在迭代过程中做任何其他事情,那么获得索引(这可以保证你能够引用它,例如,如果你有一个dicts列表)和实际的列表项内容可能会很好。

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是您以后要删除的索引不会改变的。

答案 11 :(得分:4)

您可能希望使用filter()作为内置功能。<​​/ p>

有关详细信息check here

答案 12 :(得分:3)

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

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

答案 13 :(得分:3)

您可以尝试反向循环,因此对于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元素)。

答案 14 :(得分:2)

我需要做类似的事情,在我的情况下,问题是内存 - 我需要合并列表中的多个数据集对象,在做了一些东西后,作为一个新对象,并需要摆脱每个条目我正在合并,以避免重复所有这些并炸毁记忆。在我的情况下,字典中的对象而不是列表工作正常:

```

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

```

答案 15 :(得分:2)

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的this回答(相关问题)。这解释了在迭代已修改的列表时如何更新数组索引。下面的解决方案旨在正确跟踪数组索引,即使列表已被修改。

here 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。也可以使用切片修改列表(sortreverse方法未实现)。

唯一的条件是,您必须只修改列表,如果在任何时候将fluidLl重新分配给不同的列表对象,则代码将无效。原始的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循环中使用(并修改)相同的iterable。

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

编辑:正如评论中所提到的,这个答案实际上并不存在这种方法提供解决方案的问题。我将尝试在此解决这个问题:

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

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]

答案 16 :(得分:2)

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

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

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

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

答案 17 :(得分:2)

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

示例:

i = 0
length = len(list1)

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

    i += 1

答案 18 :(得分:1)

其他答案是正确的,从您正在迭代的列表中删除通常是个坏主意。反向迭代避免了陷阱,但是遵循这样做的代码要困难得多,所以通常你最好使用列表解析或filter

但是,有一种情况是可以安全地从您正在迭代的序列中删除元素:如果您只是在迭代时删除一个项目。这可以使用returnbreak来确保。例如:

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

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

答案 19 :(得分:1)

最有效的方法是列表理解,很多人展示了他们的情况,当然,这也是通过ucwords($option)获得iterator的好方法。

  

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

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

False

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

答案 20 :(得分:1)

我可以想到三种解决您的问题的方法。例如,我将创建一个元组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更有效。我首选方法2 。对于上述示例,time(method1) : time(method2) : time(method3) = 1 : 1 : 1.7

答案 21 :(得分:1)

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等

答案 22 :(得分:0)

问题在于列表是可变对象

import re
result = re.search(r"([0-9])\1\1","14551114")) 
# <re.Match object; span=(4, 7), match='111'>
print(result.group() 
# '111'

随着idx的发展,mylist也随之缩小。

#+begin_src ipython :session alinbx :results output
mylist = list(range(8))
idx = 0
for i in mylist:
    print(f"i={i}, idx={idx}, mylist{[idx]}={mylist[idx]}, {mylist}")
    mylist.remove(i)
    idx += 1

#+end_src

#+RESULTS:
: i=0, idx=0, mylist[0]=0, [0, 1, 2, 3, 4, 5, 6, 7]
: i=2, idx=1, mylist[1]=2, [1, 2, 3, 4, 5, 6, 7]
: i=4, idx=2, mylist[2]=4, [1, 3, 4, 5, 6, 7]
: i=6, idx=3, mylist[3]=6, [1, 3, 5, 6, 7]

答案 23 :(得分:0)

我认为删除元素时使用while和un-increment是最简单的方法。

import random

def f(l, n):
    # n shall not pass
    idx = 0
    while idx < len(l):
        if l[idx] % 2 == n:
            del l[idx]
            continue
        idx += 1


res = [random.randrange(1, 50) for i in range(10000)]
f(res, 0)
f(res, 1)

最后,res应该是[]。

答案 24 :(得分:0)

嗨,我遇到以下问题:

我想遍历2个列表,如果两个列表中都包含obj,则将其删除。最后,仍然应该有2个列表,这两个列表之间存在差异。

然后我有与此问题相同的索引问题。

我认为我找到了解决索引问题的好方法,并希望与您分享。

def get_diff(list1,list2):

    index = 0
    for obj in list1[index:]:
        if obj in list2:
            list1.remove(obj)
            list2.remove(obj)
        else:
            index += 1


    return list_rep_vols,list_aix_vols

我将索引定义为var,并告诉list1从索引开始迭代到list1的末尾。因此,从技术上讲,我告诉他,如果删除索引0,则索引1现在就是索引0。

这里有个例子:

test = ["a", "z", "b", "f", "d"]
test1 = ["a", "b", "c", "e"]

test_re, test1_re = get_del_and_add_list_aix(test,test1)

print(test_re)
print(test1_re)

输出:

  

测试['z','f','d']

     

test1 ['c','e']

致谢

chrisaramar

答案 25 :(得分:0)

假设一个数字列表,您想删除所有可被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)

答案 26 :(得分:0)

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

for i in li:
    i = None

for elem in li:
    if elem is None:
        continue

通过这种方式,您无需复制列表,而且更容易理解。

答案 27 :(得分:0)

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

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

""" 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

答案 28 :(得分:0)

对于任何可能具有很大潜力的东西,我使用以下内容。

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)

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

答案 29 :(得分:-1)

您想立即创建列表副本,以便在迭代并删除该列表中符合特定条件的元组时将其作为参考。

然后,它取决于输出所需的列表类型,无论是已删除元组的列表还是未删除的元组列表。

正如大卫指出的那样,我建议使用列表理解来保留你不想删除的元素。

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