给定表示范围的元组列表,压缩范围(写一个函数)

时间:2017-12-05 14:50:53

标签: python python-2.7

我正在学习Python 2.x并希望解决以下问题。 需要一个函数来压缩范围

问题:给定代表范围的元组列表,压缩范围

Input : [(2,3),(4,5),(7,8),(8,10),(12,15)]
Output :[(2,5),(7,10),(12,15)]

任何指针或帮助都会很有帮助

2 个答案:

答案 0 :(得分:0)

您可以按照下面的示例继续操作。我们的想法是处理单个区间(lb, ub),并为每个下限lb标记增加1,而对于每个上限ub,标记减少-1。 假设整数输入,代码有效地考虑了区间(lb-0.5,ub+0.5),以便合并例如(2, 3)(4, 5)。为了避免将浮点数用作字典键,字典stat将数字加倍......

当您处理这些单独的“中断”点时,总累计值(cnt)会告诉您当前点的间隔数。只要此数字大于零,我们就在合并的段内。如果它下降到零,我们可以采取下一个断点并重复该过程......

spec = {}
L = [(2,3),(4,12),(7,8),(8,10),(12,15)]
for lb, ub in L:
    lb, ub = min(lb, ub), max(lb, ub)
    for v in [2*lb - 1, 2*ub + 1]:
        if not v in spec: spec[v] = 0
    spec[2*lb - 1] += 1
    spec[2*ub + 1] -= 1

break_points = sorted(spec.keys())
N = len(break_points)

idx = -1
while idx < N-1:
    idx += 1

    lb, ub = break_points[idx], None
    cnt = spec[lb]

    while cnt > 0:
        idx += 1
        ub = break_points[idx]
        cnt += spec[ub]

    print((lb+1)/2, (ub-1)/2)
    #prints (2, 15)

答案 1 :(得分:0)

合并范围并不像看起来那么容易和简单。你必须注意多个输入范围的重叠,以及包含,i / e范围完全包含在另一个输入范围内。

还必须确保输入按起始值排序。

这是一个经过时间考验的解决方案:

def overlap(r1, r2):
    return r1[1] >= r2[0] - 1    # <-- -1 to ensure ranges like (2, 3) and (4, 5) merge into (2, 5)

def merge_range(r1, r2):
    s1, e1 = r1
    s2, e2 = r2
    return (min(s1, s2), max(e1, e2))

def regroup_ranges(rgs):
    assert all([s <= e for s, e in rgs])
    if len(rgs) == 0:
        return rgs

    rngs.sort()

    regrouped = [rgs[0]]

    for r2 in rgs[1:]:
        r1 = regrouped.pop()
        if overlap(r1, r2):
            regrouped.append(merge_range(r1, r2))
        else:
            regrouped.append(r1)
            regrouped.append(r2)

    return regrouped

试验:

def test_regroup_ranges():
    rngs = [(2, 3), (4, 5), (7, 8), (8, 10), (12, 15)]
    compressed = [(2, 5), (7, 10), (12, 15)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = [(2, 8), (4, 5), (7, 8), (8, 10), (12, 15)]
    compressed = [(2, 10), (12, 15)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = [(2, 3) ,(4, 5), (1, 16), (8, 10), (12, 15)]
    compressed = [(1, 16)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = [(2, 3), (4, 20), (7, 8), (8, 10), (12, 15)]
    compressed = [(2, 20)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = [(2, 3), (5, 8), (10, 12)]
    compressed = [(2, 3), (5, 8), (10, 12)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = [(2, 3)]
    compressed = [(2, 3)]
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    rngs = []
    compressed = []
    print(regroup_ranges(rngs))
    assert regroup_ranges(rngs) == compressed

    print("***all tests pass***")

test_regroup_ranges()

测试结果:

[(2, 5), (7, 10), (12, 15)]
[(2, 10), (12, 15)]
[(1, 16)]
[(2, 20)]
[(2, 3), (5, 8), (10, 12)]
[(2, 3)]
[]
***all tests pass***