如何检查一组范围中是否存在数字?

时间:2013-05-17 11:46:23

标签: javascript jquery python django

R1=[0,20]
R2=[15,20]
R3=[30,50]
Target=[0,50]

我需要检查所有R(s)是否涵盖了目标范围。

在上面的例子中, 0..20和30..50被覆盖但不是20..30

是否有一种简单的方法可以检查它?

循环显示所有数字会降低性能,因为实际上我需要处理10000个范围。

我可以在服务器端使用Python-django,也可以在客户端使用jquery。

6 个答案:

答案 0 :(得分:3)

使用sympy

from sympy import Interval

coverage = Interval(0,20) + Interval(15,20) + Interval(30,50)
target = Interval(0, 50)

return coverage.subset(target)

或者如果您需要实际结果:

>>> target - coverage
(20, 30)

答案 1 :(得分:1)

除非您的范围存储,否则您必须访问每个范围,因为一个范围可能包含最小值/最大值。因此对于N范围,您可能具有的最差运行时间将是O(N)。所以像这样:

Ranges = [[0,20],[15,20],[30,50]]
def inRange(targetMin,targetMax,Ranges):
    minV,maxV = Ranges[0][0], Ranges[0][1]
    for r in Ranges:
        if r[0] < minV:
                minV = r[0]
        if r[1] > maxV:
                maxV = r[1]
        if targetMin >= minV and targetMax <= maxV: #if we're in range, no need to check the others
                return True
    else:
        return False

print(inRange(0,50,Ranges))

或非累积(其中min / max是每个范围的本地,而不是所有范围)

def inRangeNonCum(targetMin,targetMax,Ranges):
    for r in Ranges:
        if targetMin >= r[0] and targetMax <= r[1]:
                return True
    else:
        return False

print(inRangeNonCum(0,20,Ranges))
print(inRangeNonCum(30,50,Ranges))
print(inRangeNonCum(20,30,Ranges))

可生产

>>> 
True
True
False

您的预期结果。在任何一种情况下,最差时间是O(N)。如果您的范围以某种方式排序,那么您可以查看极端,如果结束的min大于targetMax,那么请说从末尾开始向后看1/4范围......

答案 2 :(得分:0)

ranges = [[0,20],[15,20],[30,50]]
target=[x for x in range(0,50+1)]
for x, y in ranges:
    range_object = range(x, y+1)
    target = list(filter(lambda x: x not in range_object, target))
    if not target:
        break

print("Not covered:" + str(target))

这应该有用,并准确地为您提供未涵盖的内容。它必须遍历所有数字,但通过使用过滤函数应该相当有效。

编辑:与@ njzk2提出的范围合并结合使用效果最佳

答案 3 :(得分:0)

您可以使用interval库:

import interval
r1 = interval.Interval(*R1)
r2 = interval.Interval(*R2)
r3 = interval.Interval(*R3)
t = interval.Interval(*Target)

In [11]: r = interval.IntervalSet([r1, r2, r3])

In [12]: r
Out[12]: IntervalSet([Interval(0, 20, lower_closed=True, upper_closed=True),
                      Interval(30, 50, lower_closed=True, upper_closed=True)])

In [13]: t_minus_r = interval.IntervalSet([t]) - r

In [14]: t_minus_r
Out[14]: IntervalSet([Interval(20, 30, lower_closed=False, upper_closed=False)])

您可以简单地测试某个值是否在给定的Interval / IntervalSet中:

In [15]: 1 in r
Out[15]: True

In [16]: 1 in t_minus_r
Out[16]: False

In [17]: 20.00001 in t_minus_r
Out[17]: True

答案 4 :(得分:0)

使用此算法

#Added a few ranges for demonstration puposes
ranges = [[25, 35], [0, 20], [5, 10], [15, 20], [30, 50]]

new_ranges = []

for range in sorted(ranges):
    for large_range in new_ranges:
        if range[0] >= large_range[0] and range[0] <= large_range[1]:
            if range[1] > large_range[1]:
                large_range[1] = range[1]
            break
    else:
        new_ranges.append(range)

print new_ranges

[[0, 20], [25, 50]]

new_ranges包含合并范围。通常,如果涵盖您的范围,它将仅包含在其中一个合并范围内。在排序时,搜索它们的速度非常快。

答案 5 :(得分:0)

似乎是Python sets的一个自然问题 - 直到经验证明你需要更快的东西。

ranges = [ [0,20], [15,20], [30,50] ]
target = [0,50]
result = set(range(target[0], target[1]))

for a,b in ranges:
    result.difference_update(range(a, b))

print result  # set([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])