Если у вас есть много значений для тестирования, вы можете использовать модуль bisect , чтобы быстрее определить, в каком диапазоне находятся значения.
Если
m
= количество проверяемых значений и
n
= len(rangelist)
затем цикл по значениям и диапазону, как вы предлагаете, займет O(m*n)
времени.
Если вы используете разделение пополам, то сначала нужно отсортировать начальные адреса O(nlogn)
и найти место каждого значения в диапазоне O(m*logn)
.
Так что если
O(nlogn + m*logn) < O(m*n)
тогда бисекция побеждает. Для больших n
, O(m*logn)
является минимальным по сравнению с O(m*n)
.
Таким образом, приведенное выше неравенство будет истинным, если
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))