python列表的子集

时间:2012-10-05 16:32:58

标签: python search data-structures

我需要找到python列表的子集,例如:

a = [[1,2,100],[1,3,2100],[2,3,200],[3,4,1600]]

假设每个元素的第一个元素表示start_time,第二个元素表示end_time,我的查询格式为(start,end)。生成的子集应该使得子集中每个元素的start_time和end_time应该在start和end之间。

最快的方法是什么(或者我应该保存数据以获得更好的运行时间的任何结构)?

3 个答案:

答案 0 :(得分:2)

您可以使用范围树来存储积分。将(start_time,end_time)对视为(x,y)坐标。然后查询(开始,结束)成为在广场[开始,结束] x [开始,结束]中找到点的问题。

可以在O(n log n)时间内计算两个维度上的范围树,并在O(log n)时间内对它们进行查询。

不幸的是,我不知道任何优秀的Python实现(可能Python Quadtree除外),因此您可能需要自己动手。但是,它肯定会比任何线性搜索解决方案都快。

如果您不想使用或编写范围树,请考虑使用NumPy代替更快的线性搜索:

arr = np.array(a)
xa, ya, val = arr.T
pts = (xa >= start) & (ya <= end)
print arr[pts]

答案 1 :(得分:1)

>>> start, end = 0, 5
>>> result = [i for i in a if start <= i[0] and end >= i[1]]
>>> print result
... [[1, 2, 100], [1, 3, 2100], [2, 3, 200], [3, 4, 1600]]

>>> start, end = 2, 3
>>> result = [i for i in a if start <= i[0] and end >= i[1]]
>>> print result
... [[2, 3, 200]]

列表理解。如果您希望它不包含,请移除=

答案 2 :(得分:1)

使用bisect module演示的算法可以为您提供最快的搜索时间,但我们必须创建一些已排序的索引。

您必须将开始时间和结束时间都存储在列表中,其中包含a列表中条目的索引:

starttimes = [(l[0], i) for i,l in enumerate(a)]
starttimes.sort()
endtimes = [(l[1], i) for i, l in enumerate(a)]
endtimes.sort()

然后,您可以根据bisectbisect.bisect_left函数创建专门的bisect.bisect_right函数:

def bisect_timeseries_start(starttimes, start):
    while lo < hi:
        mid = (lo+hi)//2
        if starttimes[mid][0] < start: lo = mid+1
        else: hi = mid
    return starttimes[lo][1]

def bisect_timeseries_end(endtimes, end):
    while lo < hi:
        mid = (lo+hi)//2
        if end < endtimes[mid][0]: hi = mid
        else: lo = mid+1
    return endtimes[lo][1]

现在您可以使用以下函数找到开始和结束索引:

startindex = bisect.bisect_timeseries_start(starttimes, start)
endindex = bisect.bisect_timeseries_end(endtimes, end)

现在可以轻松返回匹配范围:

startendrange = a[startindex:endindex]

每次搜索都有O(lg n)费用,其中n是列表的长度。将这些操作组合成一个封装时间序列列表a和索引的类很容易。