提问人:lfaraone 提问时间:7/30/2009 最后编辑:Ciro Santilli OurBigBook.comlfaraone 更新时间:1/25/2023 访问量:890989
如何在迭代时从列表中删除项目?
How to remove items from a list while iterating?
问:
我正在遍历 Python 中的元组列表,如果它们满足某些条件,我会尝试删除它们。
for tup in somelist:
if determine(tup):
code_to_remove_tup
我应该用什么来代替?我不知道如何以这种方式删除该项目。code_to_remove_tup
答:
您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,并可能导致意外结果。
例如(取决于列表的类型):
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()
对于这样的例子,最好的方法是列表推导
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 = [x for x in somelist if not determine(x)]
或者,通过分配给切片,您可以更改现有列表以仅包含所需的项目:somelist[:]
somelist[:] = [x for x in somelist if not determine(x)]
如果有其他参考资料需要反映这些变化,这种方法可能很有用。somelist
除了理解,您还可以使用 .在 Python 2 中:itertools
from itertools import ifilterfalse
somelist[:] = ifilterfalse(determine, somelist)
或者在 Python 3 中:
from itertools import filterfalse
somelist[:] = filterfalse(determine, somelist)
评论
somelist[:] = (x for x in somelist if determine(x))
PySequence_Fast()
的函数。这个函数总是返回一个列表,即@Alex已经使用列表而不是生成器的 Martelli 解决方案很可能更有效list_ass_slice()
somelist[:]=
somelist
for i in range(len(somelist) - 1, -1, -1):
if some_condition(somelist, i):
del somelist[i]
你需要倒退,否则这有点像锯掉你坐着的树枝:-)
Python 2 用户:替换为以避免创建硬编码列表range
xrange
评论
reversed()
m
reversed(xrange(len(somelist)))
reversed(range(len(somelist)))
对于那些喜欢函数式编程的人:
somelist[:] = filter(lambda tup: not determine(tup), somelist)
或
from itertools import ifilterfalse
somelist[:] = list(ifilterfalse(determine, somelist))
评论
filter
lambda
map
filter
map
filter
lambda
建议列表推导的答案几乎是正确的——除了他们构建了一个全新的列表,然后给它起了一个与旧列表相同的名称,他们没有就地修改旧列表。这与选择性删除不同,正如 Lennart 的建议一样——它更快,但如果通过多个引用访问您的列表,那么您只是重新替换其中一个引用而不更改列表对象本身这一事实可能会导致微妙的、灾难性的错误。
幸运的是,它非常容易获得列表推导的速度和就地更改所需的语义 - 只需编写代码:
somelist[:] = [tup for tup in somelist if determine(tup)]
请注意与其他答案的细微差别:这个答案没有分配给裸名。它分配给恰好是整个列表的列表切片,从而替换同一 Python 列表对象中的列表内容,而不是像其他答案一样重新替换一个引用(从以前的列表对象到新的列表对象)。
评论
a
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
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)]
您可能希望将 available 用作内置。filter()
有关更多详细信息,请查看此处
如果要在迭代期间执行任何其他操作,最好同时获取索引(这样可以保证您能够引用它,例如,如果您有一个字典列表)和实际列表项内容。
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
评论
您可以尝试反向 for 循环,因此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)))
解决方法概述
也:
使用链表实现/滚动您自己的。
链表是支持高效删除项目所需的适当数据结构,不会强制您进行空间/时间权衡。
CPython 是使用动态数组实现的,如此处所述,动态数组不是支持删除的好数据类型。
list
但是,标准库中似乎没有链表:
从头开始一个新的,最后回到最后,如以下所述: https://stackoverflow.com/a/1207460/895245
list()
.append()
这样可以节省时间,但空间效率较低,因为它在迭代期间保留了数组的额外副本。
与索引一起使用,如以下所述: https://stackoverflow.com/a/1207485/895245
del
这更节省空间,因为它分配了数组副本,但时间效率较低,因为从动态数组中删除需要将所有后续项目移回 1,即 O(N)。
一般来说,如果你是快速而肮脏的,并且不想添加自定义类,你只想默认选择更快的选项,除非内存是一个大问题。LinkedList
.append()
官方 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()
Python 能做得更好吗?
似乎这个特定的 Python API 可以改进。例如,将其与以下产品进行比较:
- Java ListIterator::remove 文档“每次调用下一个或上一个只能进行一次此调用”
- C++
std::vector::erase
,在删除元素后向元素返回一个有效的中介器
这两者都清楚地表明,除非使用迭代器本身,否则您不能修改正在迭代的列表,并且为您提供了在不复制列表的情况下进行修改的有效方法。
也许潜在的基本原理是假设 Python 列表是动态数组支持的,因此任何类型的删除无论如何都会在时间上效率低下,而 Java 具有更好的接口层次结构,具有 ArrayList
和 LinkedList
实现。ListIterator
Python stdlib 中似乎也没有显式链表类型:Python 链表
评论
我需要做类似的事情,就我而言,问题是内存 - 我需要将多个数据集对象合并到一个列表中,在对它们做了一些事情之后,作为一个新对象,并且需要删除我正在合并的每个条目,以避免复制所有这些条目并炸毁内存。就我而言,将对象放在字典而不是列表中工作正常:
```
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
```
如果当前列表项满足所需的条件,则只创建一个新列表可能是明智的。
所以:
for item in originalList:
if (item != badValue):
newList.append(item)
为了避免使用新的列表名称重新编码整个项目:
originalList[:] = newList
注意,来自 Python 文档:
复制.copy(x) 返回 x 的浅拷贝。
复制.deepcopy(x) 返回 x 的深层副本。
评论
顶级域名:
我写了一个库,允许你这样做:
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'
如果可能的话,最好使用另一种方法,在迭代时不需要修改可迭代对象,但对于某些算法来说,它可能没有那么简单。因此,如果您确定自己确实需要原始问题中描述的 Code Pattern,这是可能的。
应该适用于所有可变序列,而不仅仅是列表。
完整答案:
编辑:此答案中的最后一个代码示例给出了一个用例,说明为什么您有时可能想要就地修改列表而不是使用列表推导式。答案的第一部分是关于如何就地修改数组的教程。
该解决方案遵循 senderle 的这个答案(对于相关问题)。这解释了在循环访问已修改的列表时如何更新数组索引。下面的解决方案旨在正确跟踪数组索引,即使列表被修改也是如此。
从这里下载,它只是一个文件,所以不需要安装git。没有安装程序,因此您需要确保该文件位于您自己的 python 路径中。该代码是为 python 3 编写的,未经在 python 2 上测试。fluidIter.py
https://github.com/alanbacon/FluidIterator
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
唯一的条件是,如果在任何时候或被重新分配给不同的列表对象,则代码将不起作用,则只能就地修改列表。原始对象仍将由 for 循环使用,但将超出我们修改的范围。fluidL
l
fluidL
即
fluidL[2] = 'a' # is OK
fluidL = [0, 1, 'a', 3, 4, 5, 6, 7, 8] # is not OK
如果我们想访问列表的当前索引值,我们不能使用 enumerate,因为这只计算 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
更多示例/测试可以在 底部的部分找到。这些值得一看,因为它们解释了在各种情况下会发生什么。例如:使用切片替换列表的大部分内容。或者在嵌套的 for 循环中使用(和修改)相同的迭代对象。if __name__ is "__main__":
fluidIter.py
正如我一开始所说:这是一个复杂的解决方案,会损害代码的可读性,并使调试更加困难。因此,应首先考虑其他解决方案,例如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)]
some_list[:] = [x for x in some_list if not some_condition(y)]
y
x
some_list[:] = [x for x in some_list if not some_condition(intermediateStateOf_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[:]
这个答案最初是为了回答一个后来被标记为重复的问题而写的:从 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”来验证这一点,它不同于“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”对象。出于实际目的,您可以将其视为创建其参数的反向副本。这是我推荐的解决方案。
我需要用一个巨大的列表来做到这一点,复制列表似乎很昂贵,特别是因为在我的情况下,与剩余的项目相比,删除的数量很少。我采用了这种低级方法。
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
OrderedDict
newlist = []
newlist.append(array[i])
del array[i]
list()
list()
其他答案是正确的,从正在迭代的列表中删除通常是一个坏主意。反向迭代避免了一些陷阱,但遵循这样做的代码要困难得多,因此通常最好使用列表推导式或 .filter
但是,在一种情况下,从正在迭代的序列中删除元素是安全的:如果在迭代时只删除一个项目。这可以使用 或 .例如:return
break
for i, item in enumerate(lst):
if item % 4 == 0:
foo(item)
del lst[i]
break
当您对满足某些条件的列表中第一项执行一些具有副作用的操作,然后立即从列表中删除该项时,这通常比列表推导更容易理解。
对于任何有可能变得非常大的东西,我使用以下方法。
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.
评论
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
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 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.i
评论
The most effective method is list comprehension, many people show their case, of course, it is also a good way to get an through .iterator
filter
Filter
receives a function and a sequence. 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 or .Filter
True
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.
评论
I can think of three approaches to solve your problem. As an example, I will create a random list of tuples . The condition that I choose is . In the final list we will only have those tuples whose sum is not equal to 15. 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
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 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. 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)]
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
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.
A for loop will be iterate through an index...
Consider you have a list,
[5, 7, 13, 29, 65, 91]
You have used a list variable called . And you use the same to remove...lis
Your variable
lis = [5, 7, 13, 29, 35, 65, 91]
0 1 2 3 4 5 6
during the 5th iteration,
Your number 35 was not a prime, so you removed it from a list.
lis.remove(y)
And then the next value (65) move on to the previous index.
lis = [5, 7, 13, 29, 65, 91]
0 1 2 3 4 5
so the 4th iteration done pointer moved onto the 5th...
That’s why your loop doesn’t cover 65 since it’s moved into the previous index.
So you shouldn't reference a list into another variable which still references the original instead of a copy.
ite = lis # Don’t do it will reference instead copy
So do a copy of the list using .list[::]
Now you will give,
[5, 7, 13, 29]
The problem is you removed a value from a list during iteration and then your list index will collapse.
So you can try list comprehension instead.
Which supports all the iterable like, list, tuple, dict, string, etc.
评论
lis = [5, 7, 13, 29, 35, 65, 91]
not_primes = [35,65]
for item in not_primes: if item in lis: lis.remove(item)
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
评论