Pythonic从heapq中提取元素的方法

时间:2013-02-08 14:29:46

标签: python python-2.7 priority-queue

我正在使用优先级队列heapq)并将datetime.datetime作为优先级。

如果我有要搜索的startTime和endTime,那么从这个列表中提取元素子集的最pythonic方法是什么。 (我不能改变原始列表,所以我必须创建一个新列表并返回,或者返回一个迭代器)

以下是我的例子:

>>> import heapq
>>> timeLine = []
>>> from datetime import datetime
>>> heapq.heappush(timeLine, (datetime.now(),'A'))
>>> heapq.heappush(timeLine, (datetime.now(),'B'))
>>> heapq.heappush(timeLine, (datetime.now(),'C'))
>>> timeLine
[(datetime.datetime(2013, 2, 8, 15, 25, 14, 720000), 'A'), (datetime.datetime(2013, 2, 8, 15, 25, 30, 575000), 'B'), (datetime.datetime(2013, 2, 8, 15, 25, 36, 959000), 'C')]

真正的应用程序列表非常庞大。

2 个答案:

答案 0 :(得分:1)

堆不是执行此操作的理想结构;如果您坚持使用heapq的公共API,那么堆将被更改并且无法用于进一步的操作。 @Anonymous的解决方案可能有效,但(恕我直言)过分依赖实现细节。虽然这些是公开记录的,但我不确定你是否真的应该使用它们。

简单地对列表进行排序并进行两次二进制搜索是一种简单的方法,可以按照自己的意愿进行:

from bisect import bisect_left, bisect_right

def find_range(timeline, start, end):
    l = bisect_left(timeline, start)
    r = bisect_right(timeline, end)
    for i in xrange(l, r):
        yield timeline[i]

这种方法的唯一问题是在最坏的情况下排序需要O( n lg n )时间,但是你构建堆的方式也是如此( heapq.heapify需要线性时间。)

答案 1 :(得分:0)

堆中的每个节点都大于其所有子节点。此外,如果节点位于索引i,则其直接子节点位于索引2 * i + 1和2 * i + 2处。

将堆视为二叉树,您可以递归堆,如果条目大于您获得的maxkey(因为它的所有子项将更大),则停止,并且如果其键位于其间,则输出该节点minkey和maxkey。

把它放在一起就可以了:

def extract_range(h, i, minkey, maxkey):
    if i >= len(h) or h[i][0] >= maxkey:
        return
    if h[i][0] >= minkey:
        yield h[i]
    for k in 1, 2:
        for r in extract_range(h, 2 * i + k, minkey, maxkey):
            yield r