>>> 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)
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)
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的全新副本更干净的解决方案。反转()函数:
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)]
>>> 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']
newlist = []
for tup in somelist:
# lots of code here, possibly setting things up for calling determine
if determine(tup):
newlist.append(tup)
somelist = newlist
10条答案
按热度按时间js4nwp541#
我需要用一个巨大的列表来完成这项工作,而复制列表似乎很昂贵,特别是在我的情况下,与保留的项目相比,删除的数量很少。我采取了这种低级的方法。
我不知道的是,与复制一个大列表相比,两次删除的效率有多高。请评论,如果你有任何见解。
9rbhqvlz2#
如果当前列表项满足所需的条件,也可以创建一个新列表。
因此:
为避免使用新列表名称对整个项目重新编码:
注意,在python文档中:
copy.copy(x)返回x的浅拷贝。
复制。deepcopy(x)返回x的深度副本。
hsvhsicv3#
这个答案最初是为了回答一个被标记为重复的问题:从python上的列表中删除坐标
代码中有两个问题:
1) 使用remove()时,您尝试删除整数,而需要删除元组。
2) for循环将跳过列表中的项目。
让我们看看执行代码时会发生什么:
第一个问题是,您同时将“a”和“b”传递给remove(),但remove()只接受一个参数。那么,我们如何让remove()与您的列表一起正常工作呢?我们需要弄清楚你列表中的每个元素是什么。在本例中,每一个都是一个元组。要了解这一点,让我们访问列表中的一个元素(索引从0开始):
啊哈!l1的每个元素实际上是一个元组。这就是我们需要传递给remove()的内容。python中的元组非常简单,只需将值括在括号中即可。”a、 b“不是一个元组,但是”(a,b)“是一个元组。因此,我们修改您的代码并再次运行:
这段代码运行时没有任何错误,但让我们看看它输出的列表:
为什么(1,-2)仍在您的列表中?事实证明,在使用循环对列表进行迭代的同时修改列表是一个非常糟糕的主意,而无需特别注意。(1,-2)保留在列表中的原因是列表中每个项的位置在for循环的迭代之间发生了更改。让我们看看如果我们向上述代码提供一个更长的列表会发生什么:
从该结果可以推断,每次条件语句的计算结果为true并且删除列表项时,循环的下一次迭代将跳过对列表中下一项的计算,因为它的值现在位于不同的索引中。
最直观的解决方案是复制列表,然后迭代原始列表,只修改副本。您可以尝试这样做:
但是,输出将与之前相同:
这是因为当我们创建l2时,python实际上并没有创建新对象。相反,它只是将l2引用到与l1相同的对象。我们可以用“is”来验证这一点,它不同于仅仅“equals”(==)。
我们可以使用copy.copy()创建一个真正的副本。然后一切按预期进行:
最后,还有一个比制作l1的全新副本更干净的解决方案。反转()函数:
不幸的是,我不能充分理解
zpgglvta4#
您可以使用列表理解创建一个新列表,其中只包含您不想删除的元素:
或者,通过指定给切片
somelist[:]
,可以修改现有列表,使其仅包含所需的项:如果有其他参考文献,这种方法可能会很有用
somelist
这需要反映变化。除了理解,你还可以使用
itertools
. 在python 2中:或者在python 3中:
drnojrws5#
建议列表理解的答案几乎是正确的——除了它们构建了一个全新的列表,然后给它起了与旧列表相同的名字,它们没有修改旧列表。这与@lennart建议的选择性删除不同——它更快,但如果您的列表是通过多个引用访问的,那么您只是重新放置其中一个引用而不更改列表对象本身的事实可能会导致微妙的灾难性错误。
幸运的是,获得列表理解的速度和就地更改所需的语义非常容易——只需代码:
请注意与其他答案的细微差别:这一个答案并不是指定给一个单名,而是指定给恰好是整个列表的列表片段,从而替换同一个python列表对象中的列表内容,而不是像其他答案一样只重设一个引用(从以前的列表对象到新的列表对象)。
rbl8hiat6#
您需要获取列表的副本并首先对其进行迭代,否则迭代将失败,结果可能是意外的。
例如(取决于列表的类型):
例如:
toe950277#
你需要向后走,否则就有点像锯掉你坐的树枝:-)
python 2用户:替换
range
通过xrange
避免创建硬编码列表的步骤3htmauhk8#
变通办法概述
要么:
使用链表实现/滚动您自己的。
链表是支持高效项目删除的适当数据结构,不会强制您进行空间/时间权衡。
卡皮顿
list
使用此处提到的动态数组实现,这不是一种支持删除的好数据类型。但是,标准库中似乎没有链接列表:
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。““供发言之用”
https://docs.python.org/2/tutorial/controlflow.html#for-声明
本部分文件明确指出:
您需要制作迭代列表的副本来修改它
一种方法是使用切片表示法
[:]
如果需要在循环内部修改正在迭代的序列(例如复制选定项),建议您首先进行复制。在序列上迭代不会隐式生成副本。切片表示法特别方便:python 2文档7.3。”关于“声明”的声明
https://docs.python.org/2/reference/compound_stmts.html#for
文档的这一部分再次指出,您必须制作一份副本,并给出了一个实际的删除示例:
注意:当循环修改序列时有一个微妙之处(这只能发生在可变序列,即列表中)。内部计数器用于跟踪下一个使用哪个项,并且在每次迭代中递增。当该计数器达到序列长度时,循环终止。这意味着,如果套件从序列中删除当前(或上一个)项,则将跳过下一个项(因为它获取已处理的当前项的索引)。同样,如果套件在当前项之前的序列中插入了一个项,那么下次通过循环将再次处理当前项。这可能导致严重的错误,可以通过使用整个序列的一个片段制作临时副本来避免,例如。,
但是,我不同意这种实现,因为
.remove()
必须迭代整个列表才能找到值。python能做得更好吗?
看起来这个特定的python api可以改进。例如,将其与以下内容进行比较:
java listiterator::删除哪些文档“每次对下一个或上一个调用只能进行一次此调用”
C++
std::vector::erase
它将有效的interator返回到移除后的元素这两种方法都清楚地表明,除非使用迭代器本身,否则无法修改正在迭代的列表,并且提供了在不复制列表的情况下修改列表的有效方法。
也许其基本原理是假定python列表是动态数组支持的,因此任何类型的删除都会在时间上效率低下,而java对这两者都有更好的接口层次结构
ArrayList
及LinkedList
实现ListIterator
.python stdlib中似乎也没有显式的链表类型:python链表
mpbci0fu9#
对于这样一个例子,最好的方法是列表理解
如果你做的事情比打电话给
determine
函数,我更喜欢构造一个新列表,并在运行时简单地添加到它。例如使用复制列表
remove
可能会使您的代码看起来更干净,如下面的一个答案所述。您绝对不应该对非常大的列表执行此操作,因为这需要首先复制整个列表,然后执行O(n)
remove
对要移除的每个元素的操作,使其成为O(n^2)
算法。yquaqz1810#
对于那些喜欢函数式编程的人:
或