在python中,
有一个整数列表,列表中的每个连续整数形成一个范围。对于给定的数字,我想找到数字所属的范围,并返回范围(或范围的开头)。 E.g。
清单:
[1, 8, 11, 20, 37, 66, 99, 120, ...... ,56000,59001, .....]
号码:
100
结果:
(99,12) OR 99
数字按递增顺序排列,形成的区域不重叠,列表的大小始终是2的倍数。
列表可能很长,需要检查很多数字。
我试图将整数打包到intervalTree中,并使用search()函数进行检查,但它似乎很慢:
for i in integerList:
t = IntervalTree(Interval(*iv) for iv in zip(*[iter(annotation_dict.get(i))] * 2))
t.search(theNumber)
是否可以更快或更好地完成?谢谢。
答案 0 :(得分:1)
由于您的列表已经排序,bisect module是您的朋友。它会为你做O(log(n))搜索。
例如,函数bisect_right
和bisect_left
非常方便。如果bisect_right
返回奇数,则您的数字在一个范围内,该范围的开头是返回值减去1
。如果是偶数,那么您的数字在列表的两个不同范围之间。
请参阅下面的示例代码,我直接从结果中减去一个,因此与解释相比,我测试的是反向。
import bisect
loi = [1, 8, 11, 20, 37, 66, 99, 120, 56000, 59001]
idx = bisect.bisect_right(loi,100)-1
if idx%2 == 0:
print loi[idx]
else:
print "not in a range"
答案 1 :(得分:0)
您可以使用二进制搜索的修改来提高平均时间复杂度。 1)首先将给定数字与列表的中间元素进行比较。如果它比右半部分的中间更大,则将其与左半部分的中间进行比较。 2)继续第一步,直到得到数字所在的间隔。
答案 2 :(得分:0)
这可能不会更快,但这是一个可能的解决方案(特别是如果您需要避免每次创建IntervalTree的开销)。
def find_range(num, the_list):
midpt = len(the_list) / 2
left_list = the_list[0:midpt]
right_list = the_list[midpt:]
if num >= left_list[midpt - 1] and num <= right_list[0]:
rv = (left_list[midpt - 1], right_list[0])
elif num < left_list[midpt - 1]:
rv = find_range(num, left_list)
else:
rv = find_range(num, right_list)
return rv
我用一个小样本测试它,它按预期工作,但我会根据IntervalTree解决方案对此解决方案进行基准测试,看看你是否获得/失去了任何东西。
祝你好运!答案 3 :(得分:0)
您可以使用Python的bisect
库,如下所示:
import bisect
loi = [1, 8, 11, 20, 37, 66, 99, 120, 56000, 59001]
index = bisect.bisect_left(loi, 100)
print "({},{})".format(loi[index-1], loi[index])
这将显示以下输出:
(99,120)
它假定值在第一个和最后一个元素内。