Python:有效地删除列表前面附近的元素?

时间:2013-04-24 03:00:43

标签: python arrays list deque

有没有办法从一长串数字的开头删除元素?现在我正在做del arr [i:i + x],但它很慢,因为它必须将所有内容移动到该点左侧,这对于大型列表来说非常耗时。

我调查了deques但不确定这些是否适用于此。可以用一些方向!

5 个答案:

答案 0 :(得分:3)

deque在这里适用,你应该使用它们,如果它们非常靠近前面它会非常快,但如果起始索引位于中间位置则会慢一些。

  

索引访问在两端都是O(1),但在中间减慢到O(n)。

>>> from collections import deque
>>> def delete_slice(d, start, stop):
        d.rotate(-start)
        for i in range(stop-start): # use xrange on Python 2
            d.popleft()
        d.rotate(start)


>>> d = deque(range(15))
>>> delete_slice(d, 5, 10)
>>> d
deque([0, 1, 2, 3, 4, 10, 11, 12, 13, 14])

注意:如前所述,旋转过中间位置会很慢,如果你想从右侧支持快速删除,你可以像这样扩展代码:

def delete_slice(d, start, stop):
    stop = min(stop, len(d)) # don't go past the end
    start = min(start, stop) # don't go past stop
    if start < len(d) // 2:
        d.rotate(-start)
        for i in range(stop-start): # use xrange on Python 2
            d.popleft()
        d.rotate(start)
    else:
        n = len(d) - stop
        d.rotate(n)
        for i in range(stop - start):
            d.pop()
        d.rotate(-n)

当然还有一些其他的错误检查,你需要做,但为了简单起见,我会把它留在这里。遗憾的是,deque本身尚未提供这些方法,因此您必须像这样实现它们。

  

要实现双端切片,请使用类似的方法应用rotate()将目标元素置于deque的左侧。使用popleft()删除旧条目,使用extend()添加新条目,然后反转轮播。通过该方法的微小变化,可以轻松实现Forth样式堆栈操作,例如dup,drop,swap,over,pick,rot和roll。

答案 1 :(得分:1)

是的,deque适用于此处。准备了一个展示如何使用它的例子:

import collections

"create deque from list"
d=collections.deque([1,2,3,4,5,6])
"remove first element"
d.popleft()

print d

输出:

deque([2,3,4,5,6])

答案 2 :(得分:0)

如果您连续进行多次删除,使用带过滤器的生成器创建新列表可能更有效:

arr = [e for e in arr if not rejected(e)]

如果需要使用索引,可以使用enumerate:

arr = [e for i, e in enumerate(arr) if not rejected(i)]

两个操作都是O(n)(空间中的O(2 * n)),而连续执行多个删除是O(n * m)(但空间中的O(n))。

deque有这个特征,可能不是你想要的:

  

索引访问在两端都是O(1),但在中间减慢到O(n)。

答案 3 :(得分:0)

我想你可能想要一棵树或跳过清单。

我前段时间研究过Python树的实现: http://stromberg.dnsalias.org/~strombrg/python-tree-and-heap-comparison/

您可能最好在网站的算法部分询问此事。

答案 4 :(得分:0)

列表未针对在前面追加或弹出进行优化。不过,双端队列是。

还要注意 the CPython implementation 中的 deque.remove(item) 将从前面搜索。如果您需要频繁移动/删除队列项目,您可能会受益于考虑大多数要删除的项目是否将接近尾声,如果是这种情况,则使用翻转的队列,即 appendleftpop而不是 appendpopleft