
[英]Fastest way to check if the set contains numbers in a given range in Python
[英]Which is the fastest way to search a value within a set of many “range” objects in Python
我有很多这样的Python对象的列表:
class RangeClass(object):
def __init__(self,address,size):
self.address=address
self.size=size
#other attributes and methods...
然后,我有一个RangeClass对象的列表(rangelist)。
我需要找到给定值在哪个范围内。
我可以使用如下代码:
for r in ragelist:
if(value>=r.address and value<(r.address+r.size)):
return r
return None
但是我认为有一种更快的方法。 范围具有任意大小,但是我们可以假定它们没有重叠。
谢谢。
如果要测试的值很多,则可以使用bisect模块更快地找到值在哪个范围内。
如果
m
=要测试的值的数量,以及 n
= len(rangelist)
然后按照您的建议遍历值和范围列表,将花费O(m*n)
时间。
如果使用二等分,则必须首先对起始地址O(nlogn)
排序,然后在范围列表O(m*logn)
找到每个值的位置。 因此,如果
O(nlogn + m*logn) < O(m*n)
然后二等分获胜。 对于大n
,与O(m*n)
相比, O(m*logn)
很小。 因此,如果
O(nlogn) < O(m*n)
或等效地,当
C log(n) < m
对于一些常数C
因此,当n
大且C log(n) < m
,您可以尝试类似
import bisect
class RangeClass(object):
def __init__(self,address,size):
self.address=address
self.size=size
def __str__(self):
return '[{0},{1})'.format(self.address,self.address+self.size)
def __lt__(self,other):
return self.address<other.address
rangelist=sorted([RangeClass(i,1) for i in (1,3,4,5,7.5)])
starts=[r.address for r in rangelist]
def find_range(value):
start_idx=bisect.bisect(starts,value)-1
try:
r=rangelist[start_idx]
except IndexError:
return None
start=r.address
end=r.address+r.size
if start<=value<end:
return rangelist[start_idx]
return None
print(','.join(str(r) for r in rangelist))
for value in (0,1,1.5,2,3,4,5,6,7,8,9,10):
r=find_range(value)
if r:
print('{v} in {r}'.format(v=value,r=str(r)))
else:
print('{v} not in any range'.format(v=value))
并不是的。 您所能做的就是利用Python的关系运算符链接。
if r.address <= value < (r.address + r.size):
您还可以在RangeClass
上定义__contains__
,以允许您使用in
来查找它。
class RangeClass(object):
...
def __contains__(self, val):
return self.address <= val < (self.address + self.size)
...
if value in r:
在Range中实现比较运算符,对范围列表进行排序,并使用bisect搜索值所属的范围:
import bisect
def find_range(value):
index = bisect.bisect(rangelist, value)
if index not in (0, len(rangelist)):
index -= 1
return rangelist[index]
谢谢大家
我实际上正在使用unutbu提出的方法。
此外,我添加了另一个优化:
if(value <= first_range_value or value >= last_range_value):
return None
其中first_range_value和last_range_value之前已经计算过,它们是最小的r.address值和最大的r.address + r.size值。
这在我的应用程序中值得,但实际上取决于范围和值的分布。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.