简体   繁体   English

从python中的列表中删除元素

[英]removing element from a list in python

Is there any way of removing an element from a list in python in O(1) complexity.ie, remove(value): this searches linearly through the list and removes right.? 是否有任何方法可以在O(1)complexity.ie中删除python中的元素。删除(值):这将在列表中线性搜索并删除右键。 So, is there any way to delete an element in O(1) complexity by specifying index or value? 那么,有没有办法通过指定索引或值来删除O(1)复杂度中的元素?

When input list of size 100000 is given to the following code,it is exceeding time limit..,even after using "del". 当以下代码给出大小为100000的输入列表时,即使使用“del”,它也超过了时间限制..

l=map(int,raw_input("").split(" "))
n=l[0]
k=l[1]
s=map(int,raw_input("").split(" "))
s=sorted(s)
count=0
tree=[]
while len(s)>0:
    poset=[]
    indices=[]
    i=0
    poset.append(s[i])
    indices.append(0)
    j=i+1
    while j<len(s):
       if s[j]==k*s[i]:
           poset.append(s[j])
           indices.append(j)
           i=j
        j+=1
    tmp=0
    for i in indices:
        del s[i-tmp]
        tmp+=1                  
    tree.append(poset)

for i in tree:
    if len(i)%2==0:
        count+=(len(i))/2
    else:
        count+=(len(i)+1)/2
print count

Formally not. 正式没有。

If you know C++ Python lists are implemented more or less as std::vector s of of pointers to objects (in C parlance they are pointers to a contiguous array of pointers). 如果您知道C ++ Python列表或多或少地实现为std::vector s指向对象的指针(在C语言中它们是指向连续指针数组的指针)。 This gives O(1) access to element given the index and allows resizing, however deleting an element from the list requires shifting all subsequent elements down by one element to fill the gap. 这给了O(1)访问给定索引的元素并允许调整大小,但是从列表中删除元素需要将所有后续元素向下移动一个元素以填补空白。

Note however that what are moved are just pointers and this is done without needing to fix reference counters and so it's extremely fast (basically just a single memmov call). 但是请注意,移动的只是指针而且无需修复引用计数器就可以完成,所以它非常快(基本上只是一个memmov调用)。 The time required for the shifting is extremely small unless the list is huge. 除非清单很大,否则换班所需的时间非常短。

So deleting an element from a list in Python if the index is known using del L[index] is formally O(N) but with a tiny constant factor. 因此,如果使用del L[index]知道索引,则从Python中的列表中删除元素正式为O(N)但具有微小的常数因子。

It would be possible to implement list objects so that you can get constant time removal from either end by adding a "phase" value to the list object. 可以实现list对象,以便通过向列表对象添加“阶段”值,从任一端获取恒定时间。 This would keep access O(1) (with a slightly larger constant) but also allowing del L[0] to be O(1) making it similar to a deque . 这将保持访问O(1) (具有稍大的常数)但也允许del L[0]O(1)使其类似于deque

This however was considered and not implemented because it would make list access more complex for a normal case and optimize for a special case for which you have a specific structure deque . 然而,这被考虑并且没有实现,因为它会使list访问对于正常情况更复杂并且针对具有特定结构deque的特殊情况进行优化。 It would also break compatibility with any C extension module accessing lists. 它还会破坏与任何C扩展模块访问列表的兼容性。

Is there any way to delete an element in O(1) complexity by specifying index or value? 有没有办法通过指定索引或值来删除O(1)复杂度中的元素?

If you know what the index is, then 如果你知道索引是什么,那么

del L[index]

works very quickly (but, surprisingly not O(1) -- https://www.python.org/dev/peps/pep-3128/#motivation ). 工作得非常快(但令人惊讶的是不是O(1) - https://www.python.org/dev/peps/pep-3128/#motivation )。 If you just know the value, well it could be anywhere, so you'll have to search for it. 如果您只知道价值,那么它可能在任何地方,所以您必须搜索它。 On average it'll have to check half the elements, so this is O(N). 平均而言,它必须检查一半的元素,因此这是O(N)。

Other data structures can help. 其他数据结构可以帮助。 If you only want to know what the distinct elements are (and don't care about the order), you can use a set. 如果您只想知道不同的元素是什么(并且不关心顺序),您可以使用集合。

s = set(['1','b', '1', 'a', 1])
s
s.remove(1)
s

yields output 产量

{1, '1', 'a', 'b'}
{'1', 'a', 'b'}

and the remove command is (basically) O(1) 删除命令是(基本上)O(1)

Open a python terminal (eg jupyer) and try this: 打开一个python终端(例如jupyer)并试试这个:

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[0] # O(?)
322 ms ± 1.68 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = list(range(10000000))
...: del l[0] # O(?)
195 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: del l[-1] # O(?)
306 ms ± 2.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>>: %%timeit
...: l = list(range(10000000))
...: del l[-1] # O(?)
267 ms ± 2.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: l.append(500) # O(1)
299 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
...: l = list(range(10000000))
...: l.append(500) # O(1)
265 ms ± 1.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = [i for i in range(10000000)]
...: max(l) # O(n)
463 ms ± 15.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = list(range(10000000))
...: max(l) # O(n)
335 ms ± 10.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: from collections import deque # lets compare with deque

>>>: %%timeit
...: l = deque(range(10000000))
...: max(l) # O(n)
365 ms ± 1.83 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

>>>: %%timeit
...: l = deque(range(10000000))
...: l.append(500) #O(1)
283 ms ± 5.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = deque(range(10000000))
...: del l[0]
279 ms ± 2.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

>>>: %%timeit
...: l = deque(range(10000000))
...: del l[9999999]
286 ms ± 3.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

As you see, removing an item by index from a deque has a complexity of O(1), while removing from a list by index is sligthly more expansive but still quite constant compared to other O(n) operations like maximum computation. 如您所见,从双端队列中通过索引删除项目具有O(1)的复杂性,而通过索引从列表中删除更加宽松,但与其他O(n)操作(如最大计算)相比仍然非常稳定。 This is coherent with @6502 answer. 这与@ 6502答案一致。 Anyway, if you need to use the directed list initializer, differences are very very little because the time is dominated by the costruction procedure. 无论如何,如果你需要使用有向列表初始化器,差异非常小,因为时间由构造过程控制。 The directed initialization through the call to the actual constructor is preferable. 通过调用实际构造函数的定向初始化是更可取的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM