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

2024-11-15 08:36:00
admin
原创
12
摘要:问题描述:我正在 Python 中迭代元组列表,并尝试在它们满足某些条件时删除它们。for tup in somelist: if determine(tup): code_to_remove_tup 我应该用什么来代替code_to_remove_tup?我不知道如何以这种方式删除...

问题描述:

我正在 Python 中迭代元组列表,并尝试在它们满足某些条件时删除它们。

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

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


解决方案 1:

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

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)

解决方案 2:

建议使用列表推导的答案几乎是正确的——除了它们会构建一个全新的列表,然后给它赋予与旧列表相同的名称,它们不会就地修改旧列表。这与你通过选择性删除所做的不同,就像Lennart 的建议一样——它更快,但如果你的列表是通过多个引用访问的,那么你只是重新放置其中一个引用而不是改变列表对象本身,这可能会导致微妙的、灾难性的错误。

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

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

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

解决方案 3:

您需要先复制列表并对其进行迭代,否则迭代将失败,并可能产生意外结果。

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

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

解决方案 4:

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

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

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

解决方案 5:

解决方法概述

任何一个:

  • 使用链接列表实现/自己动手。

链表是支持有效删除项目的适当数据结构,并且不会强迫您进行空间/时间权衡。

如此处所述, CPythonlist是用动态数组实现的,这不是一种支持删除的良好数据类型。

然而标准库中似乎没有链接列表:

+ Python 中是否有链表预定义库?
+ https://github.com/ajakubek/python-llist
  • 从头开始list(),然后.append()回到最后,如所述: https: //stackoverflow.com/a/1207460/895245

这种方法时间效率高,但空间效率较低,因为它在迭代过程中会保留数组的额外副本。

  • 使用del索引,如中所述: https: //stackoverflow.com/a/1207485/895245

由于它分配了数组副本,因此这种方法更节省空间,但时间效率较低,因为从动态数组中删除需要将所有后续项目向后移动一位,即 O(N)。

一般来说,如果您做得又快又粗糙,并且不想添加自定义LinkedList类,那么您只想默认选择更快的.append()选项,除非内存是一个大问题。

官方 Python 2 教程 4.2。“for 语句”

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()必须迭代整个列表才能找到值。

Python 可以做得更好吗?

看起来这个特定的 Python API 可以改进。例如,将其与以下内容进行比较:

  • Java ListIterator::remove记录了“每次调用下一个或上一个时只能进行一次此调用”

  • C++std::vector::erase返回被移除元素之后的一个有效迭代器

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

也许根本原因是 Python 列表被认为是动态数组支持的,因此任何类型的删除都会是时间低效的,而 Java 具有更好的接口层次结构,同时具有ArrayListLinkedList的实现ListIterator

Python stdlib 中似乎也没有明确的链表类型:如何在 Python 中使用链表?

解决方案 6:

对于这样的例子,最好的方法是使用列表理解

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)

解决方案 7:

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

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

或者

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

解决方案 8:

我需要用一个很大的列表来做这件事,而复制列表似乎代价高昂,尤其是因为在我的例子中,删除的数量与保留的项目相比很少。我采用了这种低级方法。

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

我不知道删除几条命令与复制大量列表相比效率如何。如果您有任何见解,请发表评论。

解决方案 9:

这里的大部分答案都希望您创建列表的副本。我有一个用例,其中列表很长(110K 个项目),而更明智的做法是继续减少列表。

首先你需要用 while 循环替换 foreach 循环

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

在 if 块中,的值i不会改变,因为一旦旧项目被删除,您就会希望从同一索引获取新项目的值。

解决方案 10:

如果当前列表项满足所需条件,那么创建一个新列表可能也是明智之举。

所以:

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

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

originalList[:] = newList

注意,来自 Python 文档:

copy.copy(x) 返回 x 的浅拷贝。

copy.deepcopy(x) 返回 x 的深层复制。

解决方案 11:

这个答案最初是为了回答一个后来被标记为重复的问题而写的:
从 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)]

从结果中您可以推断出,每次条件语句的计算结果为真并且列表项被删除时,循环的下一次迭代将跳过对列表中下一个项的计算,因为它的值现在位于不同的索引处。

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

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' 来验证这一点,它与单纯的“equals”(==)不同。

>>> 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”对象。出于实际目的,您可以将其视为创建其参数的反向副本。这是我推荐的解决方案。

解决方案 12:

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

例子:

i = 0
length = len(list1)

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

    i += 1

解决方案 13:

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

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

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

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

解决方案 14:

如果您想在迭代期间做任何其他事情,最好同时获取索引(这保证您能够引用它,例如如果您有一个字典列表)和实际列表项内容。

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这样,您稍后要删除的索引就不会发生改变。

解决方案 15:

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

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

解决方案 16:

for循环将遍历索引......

假设你有一个列表,

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

您使用了名为 的列表变量lis。并且您使用相同的变量来删除...

你的变量

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

在第五次迭代中,

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

lis.remove(y)

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

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

因此第 4 次迭代完成指针移动到第 5 次......

这就是为什么你的循环没有覆盖 65,因为它被移动到了前一个索引。

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

ite = lis # Don’t do it will reference instead copy

因此使用 复制列表list[::]

现在你要给予,

[5, 7, 13, 29]

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

因此你可以尝试列表理解。

它支持所有可迭代的对象,如列表、元组、字典、字符串等。

解决方案 17:

您可能希望使用filter()可用作为内置功能。

欲了解更多详情,请点击此处

解决方案 18:

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

解决方案 19:

我需要做一些类似的事情,在我的例子中,问题出在内存上——我需要将列表中的多个数据集对象合并为一个新对象,然后对它们进行一些操作,并删除我正在合并的每个条目,以避免重复所有条目并耗尽内存。在我的例子中,将对象放在字典中而不是列表中效果很好:

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

解决方案 20:

最有效的方法就是列表理解,很多人都会展示自己的案例,当然这也是获得通过的好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]

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

解决方案 21:

总结:

我编写了一个库,可以让你这样做:

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`.extendsortreverse`

唯一的条件是,您只能就地修改列表,如果在任何时候fluidL或被l重新分配给不同的列表对象,代码将无法工作。原始fluidL对象仍将被 for 循环使用,但超出了我们修改的范围。

IE

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 的回答中提到的列表推导。话虽如此,我发现这个类对我来说很有用,而且比跟踪需要删除的元素的索引更容易使用。


编辑:正如评论中提到的,这个答案并没有真正提出一个问题,而这种方法可以提供解决方案。我将尝试在这里解决这个问题:

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

IE

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]

解决方案 22:

如果后面还要用到新的列表,可以简单的将elem设置为None,然后在后面的循环中再判断,就像这样

for i in li:
  if some_condition:
    li[li.index(i)] = None

for elem in li:
    if elem is None:
        continue

这样,您就不需要复制列表并且更容易理解。

解决方案 23:

对于任何可能变得非常大的事物,我都会使用以下步骤。

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)

这应该比其他任何事情都快得多。

解决方案 24:

在某些情况下,您所做的不仅仅是一次过滤列表中的一项,您还希望迭代在迭代时发生变化。

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

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

解决方案 25:

我能想到三种方法来解决你的问题。例如,我将创建一个元组的随机列表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.>构造一个新列表,其中包含不满足给定条件的元素(元组)(这与删除满足给定条件的列表元素相同)。以下是代码:

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.>查找满足给定条件的索引,然后使用删除与这些索引对应的元素(元组)。以下是该代码。

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

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用