我想知道,如果在Python中有办法修改集合而不创建新集合。 E.g:
lst = [1, 2, 3, 4, 5, 6]
new_lst = [i for i in lst if i > 3]
工作正常,但会创建一个新的集合。有没有理由说Python集合缺少一个filter()
方法(或类似方法)来修改集合对象?
答案 0 :(得分:20)
如果您想这样做,请使用
lst[:] = [i for i in lst if i > 3]
这个won't be faster or save any memory,但它会改变对象,如果这是你需要的语义。
答案 1 :(得分:8)
其他答案是正确的;如果您希望指向旧列表的所有名称都指向新列表,则可以使用切片分配。
但是,这不是真正的就地创造;新列表首先在别处创建。 Sven答案中的链接很好。
原因没有一个真正在原地运作的原因是,当创建一个像这样的新列表是O(n)时,每个真正的就地项目删除都是O(k )本身,其中k
是从删除点开始的列表长度。使用Python列表避免这种情况的唯一方法是使用一些临时存储,这是您使用切片分配所做的。
collections.deque
上的就地O(n)过滤器示例,以防您不需要将数据存储在list
中:
from collections import deque
def dequefilter(deck, condition):
for _ in xrange(len(deck)):
item = deck.popleft()
if condition(item):
deck.append(item)
deck = deque((1, 2, 3, 4, 5))
dequefilter(deck, lambda x: x > 2) # or operator.gt(2)
print deck
# deque([3, 4, 5])
答案 2 :(得分:2)
更正@larsmans original solution,您可以
i = 0
while i < len(lst):
if lst[i] <= 3:
del lst[i]
else
i += 1
或
i = len(lst)
while i > 0:
if lst[i-1] <= 3:
del lst[i-1]
i -= 1
原因是del
发生的“索引转换”。如果我在一个ceratin索引中del
,我必须重新检查该索引,因为它现在拥有不同的值。
答案 3 :(得分:1)
@Sven Marnach的lst[:]
解决方案是一种选择。您也可以使用常量额外内存使用
>>> i = 0
>>> while i < len(lst):
... if lst[i] <= 3:
... del lst[i]
... else:
... i += 1
...
>>> lst
[4, 5, 6]
...但是这个解决方案不是非常易读,并且由于所涉及的所有元素转移都需要二次时间。
答案 4 :(得分:0)
因为它是not needed。
lst[:] = [i for i in lst if i > 3]
答案 5 :(得分:0)
我认为这已经到位了;
lst = [1,2,3,4,5,6,7,8,9,10,11]
to_exclude = [8,4,11,9]
print 'lst == %s\nto_exclude == %s' % (lst,to_exclude)
for i in xrange(len(lst)-1,-1,-1):
if lst[i] in to_exclude:
lst.pop(i)
print '\nlst ==',lst
结果
lst == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
to_exclude == [8, 4, 11, 9]
lst == [1, 2, 3, 5, 6, 7, 10]