Answers:
您可以使用列表推导来创建一个仅包含您不想删除的元素的新列表:
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:
。
somelist[:] = (x for x in somelist if determine(x))
它来创建生成器,该生成器可能不会创建任何不必要的副本。
list_ass_slice()
实现somelist[:]=
调用的函数PySequence_Fast()
。这个函数总是返回一个列表,即@Alex Martelli的解决方案已经使用列表而不是生成器了,它最有可能效率更高
somelist
两种方法都不会改变原始列表吗?
暗示列表理解的答案几乎是正确的-除了它们会建立一个全新的列表,然后为其命名与旧列表相同外,它们不会修改旧列表。这与@Lennart的建议中的选择性删除操作不同-速度更快,但是如果通过多个引用访问列表,则说明您只是在重新放置其中一个引用而不更改列表对象本身可能会导致微妙的灾难性错误。
幸运的是,获得列表理解的速度和就地变更所需的语义非常容易,只需编写代码即可:
somelist[:] = [tup for tup in somelist if determine(tup)]
请注意与其他答案的细微差别:这不是分配给裸名-而是分配给恰好是整个列表的列表切片,从而替换同一Python列表对象中的列表内容 ,而不仅仅是重新放置一个引用(从先前的列表对象到新的列表对象),就像其他答案一样。
a
的内容替换dict 的内容b
,请使用a.clear(); a.update(b)
。
x = ['foo','bar','baz']; y = x; x = [item for item in x if determine(item)];
这将重新分配x
给列表理解的结果,但y
仍引用原始列表['foo','bar','baz']
。如果您期望x
并y
引用相同的列表,则可能是您引入了错误。您可以通过分配给整个列表的一部分来避免这种情况,如Alex所示,我在这里显示:x = ["foo","bar","baz"]; y = x; x[:] = [item for item in x if determine(item)];
。该列表已被修改。确保对列表的所有引用(包括此处x
和y
此处)均引用新列表。
filter
函数也会创建一个新列表,不会修改元素...仅olist[:] = [i for i in olist if not dislike(i)]
您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,并可能导致意外结果。
例如(取决于列表的类型):
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
[]
list(somelist)
将可迭代对象转换为列表。somelist[:]
制作支持切片的对象的副本。因此,他们不一定要做相同的事情。在这种情况下,我想复制该somelist
对象,因此我使用[:]
remove()
每次迭代都必须遍历整个列表,所以这将是永远的。
for i in range(len(somelist) - 1, -1, -1):
if some_condition(somelist, i):
del somelist[i]
您需要向后走,否则就像将您坐在的树枝锯掉一样:-)
Python 2用户:替换range
为xrange
以避免创建硬编码列表
reversed()
内置
enumerate
返回迭代器并reversed
需要一个序列。reversed(list(enumerate(somelist)))
如果您不介意在内存中创建额外的列表,我想您可以这样做。
m
速度可能会慢一些。
官方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()
返回到结尾:https : //stackoverflow.com/a/1207460/895245
这种时间效率高,但空间效率低,因为它在迭代期间会保留阵列的副本。
使用del
带有索引:https://stackoverflow.com/a/1207485/895245
由于它分配了数组副本,因此空间效率更高,但由于CPython列表是使用动态数组实现的,因此时间效率较低。
这意味着要删除项目,需要将所有随后的项目后退一个,即O(N)。
通常.append()
,除非内存是一个大问题,否则默认情况下,您只想使用默认选项。
Python可以做得更好吗?
似乎可以改进此特定的Python API。例如,将其与:
std::vector::erase
在删除元素后将有效的插入器返回到元素两者都清楚地表明,除了使用迭代器本身之外,您无法修改要迭代的列表,并为您提供了无需复制列表即可进行修改的有效方法。
可能的基本原理是,假定Python列表是由动态数组支持的,因此,任何类型的删除都将在时间上效率低下,而Java具有更好的接口层次结构,同时包含ArrayList
和LinkedList
实现ListIterator
。
Python stdlib中似乎也没有明确的链接列表类型:Python链接列表
此类示例的最佳方法是列表理解
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)
对于那些喜欢函数式编程的人:
somelist[:] = filter(lambda tup: not determine(tup), somelist)
要么
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
filter
,并且具有Pythonic的功能。2.如果需要lambda
使用map
或filter
,则列表comp或genexpr 始终是更好的选择。map
并且filter
当transform / predicate函数是用C内置的Python且可迭代对象的大小不是很小时,它可能会稍快一些,但是当您需要lambda
listcomp / genexpr可以避免的时候,它们总是比较慢。
我需要使用大量列表来完成此操作,并且复制列表似乎很昂贵,尤其是因为在我的情况下,与保留的项目相比,删除的数量很少。我采用了这种低级方法。
array = [lots of stuff]
arraySize = len(array)
i = 0
while i < arraySize:
if someTest(array[i]):
del array[i]
arraySize -= 1
else:
i += 1
我不知道相对于复制大型列表而言,几次删除的效率如何。如果您有任何见解,请发表评论。
list
应该首先考虑选择作为数据结构,因为从列表中间删除数据需要花费列表长度的线性时间。如果您真的不需要随机访问第k个连续项目,可以考虑一下OrderedDict
?
newlist = []
,然后newlist.append(array[i])
才创建del array[i]
?
list()
是链表,则随机访问会很昂贵,如果list()
是数组,则删除会很昂贵,因为它们需要将所有后续元素向前移动。体面的迭代器可以使链表实现更好。但是,这可以节省空间。
如果当前列表项符合期望的条件,则仅创建一个新列表也可能很聪明。
所以:
for item in originalList:
if (item != badValue):
newList.append(item)
并且避免必须使用新的列表名称重新编码整个项目:
originalList[:] = newList
注意,来自Python文档:
copy.copy(x)返回x的浅表副本。
copy.deepcopy(x)返回x的深层副本。
此答案最初是为回答一个问题而编写的,此问题已被标记为重复: 从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”对象。出于实际目的,您可以将其视为创建其参数的反向副本。这是我推荐的解决方案。
如果要在迭代过程中执行其他任何操作,最好同时获得索引(这可以保证您能够引用它,例如,如果您有字典列表)和实际的列表项内容。
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
这样一来,您以后要删除的索引就不会改变。
您可以尝试反向进行循环,因此对于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元素)。
reversed(list(enumerate(some_list)))
比自己计算索引更简单。
一种可能的解决方案,如果您不仅要删除某些内容,而且还希望在单个循环中对所有元素执行某些操作,则很有用:
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
bad
事物,对其进行处理并且还对某个good
事物进行处理,该怎么办?
alist[:]
)复制了列表,并且由于您可能在做一些花哨的事情,因此它实际上有一个用例。好的修订是好的。接受我的投票。
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]
some_list[:] = [x for x in some_list if not some_condition(x)]
而没有实现?如果没有答案,为什么有人会相信,下载并使用带有错别字和注释掉的代码的600行库是比单行代码更好的解决方案?-1。
some_list[:] = [x for x in some_list if not some_condition(y)]
where y
与list元素不同的列表x
。也不可能写some_list[:] = [x for x in some_list if not some_condition(intermediateStateOf_some_list)]
。
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等
我可以想到三种解决问题的方法。例如,我将创建一个随机的元组列表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
在某些情况下,您要做的不仅仅是一次过滤一个列表,还希望迭代时更改迭代。
这是一个示例,其中事先复制列表是不正确的,不可能进行反向迭代,并且列表理解也不是一种选择。
""" 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
提出一个数字列表,您想删除所有可被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)