快速搜索元组列表

时间:2018-07-11 17:31:06

标签: python performance list sorting tuples

所以我从数据库中提取了许多元组列表,格式为:

ts

然后我有一个元组列表,格式为:

dataA = [('A', 'B', 'C', D, E, F), ('A', 'B', 'C', D, E, F), ...]

我需要通过匹配'A'='A','B'='B','C'='C'以及其中D> Y> E来匹配从dataA到dataB的元组。 ,我将使用值“ X”和“ F”。

'A','B','C','X'是最多16个字符的字符串。 D,E,F,Y是整数。

我尝试了许多方法来执行此操作(字符串比较,嵌套的for循环,设置交集),但是它们都很慢。做到这一点的最佳方法是什么?非常感谢

1 个答案:

答案 0 :(得分:3)

这里的关键是选择正确的数据结构。 tl; dr是一组间隔树的字典是正确的数据结构,但这对您可能没有什么意义,并且绝对没有解释如何到达那里。

在开始之前……您可以将工作推送到关系数据库吗?毕竟,这些值首先是从数据库中提取的,而优化这些类型的查找正是RDBMS的全部目的。使用正确的索引,SELECT f FROM mytable WHERE a=?, b=?, c=?, ? BETWEEN e and d应该以对数时间运行。另外,您不需要获取两个表的所有行,而只需获取匹配的行即可。


首先,您只希望其中的前三个值完全匹配的元组。因此,您需要一个以前三个成员为键,并具有匹配值的字典:

dictA = {}
for a, b, c, *d in dataA:
    dictA.setdefault((a, b, c), set()).add(tuple(d))

这已经使每个比较的范围缩小到仅对具有正确A, B, C的元组进行线性搜索,而不是对所有元组进行线性搜索。那可能已经足够了。


如果没有,如何减少线性搜索?

如果您有一个按A, B, C值排序的排序列表(或二叉搜索树或其他内容),而不是D的一组元组怎么办?然后,您可以找到第一个D > Y对数而非线性时间。但是,不幸的是,您仍然必须从头到尾扫描列表的其余部分,因为它们都有D > Y,并且在测试它们之前,您不知道哪个也有Y > E所有。因此,您只将总时间减少了50%,而不是对数。

如果您有两个排序列表,一个列表按D排序,另一个列表按E排序怎么办?乍一看,这似乎很有希望,但是如何将它们结合起来?


您实际需要做的是将元组分解为不重叠的间隔,每个间隔包含一个或多个元组。例如,如果元组A具有D=4, E=1,而元组B具有D=6, B=3,则间隔(1, 3)与元组{A},间隔(3, 4)与元组{ {1}},间隔{A, B}(4, 6)

然后,您可以将那些不相交的间隔存储在二进制搜索树(或其他对数数据结构)中。由于它们是不相交的,因此您可以按字典顺序按{B}排序,也可以按(begin, end, value)排序,以您使用的tree API中较容易的一种为准。


因此,现在,搜索是在begin上进行哈希查找,以找到由(a, b, c)排序的不相交(d, e)间隔的树,然后使用d在该树上进行对数搜索,然后检查该间隔是否为y,答案是否为该间隔内相应的d > y > e元组。


Python显然没有内置用于间隔脱节的代码,但是构建自己并不难。

实际上,PyPI上有一些库可以包装整个间隔树结构。但这并不像dict,即使您不知道哈希意味着什么,也很难使用它。一旦牢牢掌握了抽象,使用间隔树就很容易了,但是在此之前很难弄清楚。例如,您需要考虑一下开放范围(正在测试{f},而不是通常的Python半开放D < Y < E)应该如何处理边缘。因此,值得首先手动构建它。


因此,将它们放在一起,就可以像下面这样构建数据结构:

D < Y <= E

然后像这样使用它:

dictA = {}
for a, b, c, d, e, f in dataA:
    dictA.setdefault((a, b, c), set()).add((d, e, f))
for key, values in dictA.items():
    tree = IntervalTree()
    for d, e, f in values:
        tree.add(low=d, high=e, value=f)
    dictA[key] = tree

这可能不是可运行的代码,尤其是因为我怀疑任何间隔树库都完全具有此API,但这几乎就是您的代码的结构方式。