【问题标题】:Combine overlapping ranges of numbers合并重叠的数字范围
【发布时间】:2019-10-24 06:58:36
【问题描述】:

我需要将重叠的数字范围合并为单个范围。所以我有一个包含类似子列表的列表:

[[83,77],[103,97],[82,76],[101,95],[78,72],[97,91],[72,66],[89,83],[63,57],[78,72],[53,47],[65,59],[41,35],[50,44],[28,22],[34,28],[14,8],[16,10]]

因此,从 83 到 77 与 82 到 76 重叠,并将变为 76 到 83。如果任何其他范围与此范围重叠,则将其最小值和最大值添加到此范围,并且当没有其他重叠时,该方法应转到列表中的下一个并尝试将其与它的重叠合并。

我认为这是有道理的。

【问题讨论】:

  • 添加*最小值或最大值*
  • 请发布您期望的输出以及您当前的尝试。
  • 我是 python 新手,在这个问题上坐了很长时间,因为我无法围绕逻辑思考。我没有尝试,这就是为什么我首先寻求帮助。我还描述了我期望的输出。提前感谢您的理解。
  • 你只说“会变成76到83”。这是否意味着您的输出应该是[[76, 83], ...]?原始数据对是否总是按降序排列,您是否希望结果对按升序排列?
  • 首先,感谢您的反应!是的,它优化/压缩列表以便合并重叠的范围。所以这两个将成为一个,如果与它们有任何其他重叠也将被添加,因此 3 个子列表将变为 1。未指定列表的顺序,因此它可以是降序或升序。

标签: python numbers range overlap


【解决方案1】:

如果我理解正确,你可以这样做:

from itertools import combinations
l = [[83,77],[103,97],[82,76],[101,95],[78,72],[97,91],[72,66],[89,83],[63,57],[78,72],[53,47],[65,59],[41,35],[50,44],[28,22],[34,28],[14,8],[16,10]]


def any_items_overlap(l):

    # For each possible pair of lists in l
    for item1, item2 in combinations(l, 2):

        max1, min1 = item1
        max2, min2 = item2

        if min1 > max2 or max1 < min2:
            # no overlap so ignore this pair
            continue

        else:  # One of the combinations overlaps, so return them
            return item1, item2

    return None


while True:

    if not any_items_overlap(l):
        # No items overlapped - break the loop and finish
        print(l)
        break

    else:  # There are still overlaps
        item1, item2 = any_items_overlap(l)

        # Remove the items from the main list
        l.remove(item1)
        l.remove(item2)

        # Replace them with a merged version
        item_values = item1 + item2
        l.append([max(item_values), min(item_values)])
        # Start the loop again to check for any other overlaps

这给出了:

[[41, 35], [103, 91], [65, 57], [53, 44], [34, 22], [16, 8], [89, 66]]

【讨论】:

  • 非常感谢您的解决方案有效!现在我要出去一个星期,因为我很笨,我需要很多时间来理解这段代码确实......永远不会少有义务!
  • 没问题 - 我添加了一些 cmets 来解释发生了什么。
【解决方案2】:

使用 IntervalTree https://en.wikipedia.org/wiki/Interval_tree

python中有一个可用的实现:

pip install intervaltree
import intervaltree

intervals = [
    [77, 83],
    [97, 103],
    [76, 82],
    [95, 101],
    [72, 78],
    [91, 97],
    [66, 72],
    [83, 89],
    [57, 63],
    [72, 78],
    [47, 53],
    [59, 65],
    [35, 41],
    [44, 50],
    [22, 28],
    [28, 34],
    [8, 14],
    [10, 16],
]

tree = intervaltree.IntervalTree.from_tuples(intervals)

print(tree)
tree.merge_overlaps()
print(tree)
tree.merge_overlaps(strict=False)
print(tree)

请注意,我必须将您的观点设为 (start, end) 而不是 (end, start)

IntervalTree([Interval(8, 14), Interval(10, 16), Interval(22, 28), Interval(28, 34), Interval(35, 41), Interval(44, 50), Interval(47, 53), Interval(57, 63), Interval(59, 65), Interval(66, 72), Interval(72, 78), Interval(76, 82), Interval(77, 83), Interval(83, 89), Interval(91, 97), Interval(95, 101), Interval(97, 103)])

合并到

IntervalTree([Interval(8, 16), Interval(22, 28), Interval(28, 34), Interval(35, 41), Interval(44, 53), Interval(57, 65), Interval(66, 72), Interval(72, 83), Interval(83, 89), Interval(91, 103)])

strict=False 允许合并触摸间隔

IntervalTree([Interval(8, 16), Interval(22, 34), Interval(35, 41), Interval(44, 53), Interval(57, 65), Interval(66, 89), Interval(91, 103)])

【讨论】:

  • 也感谢您的解释和帮助!
  • 想要注意的是,如果您使用大量间隔,这将更加可靠。自定义版本的逻辑将允许额外的改进,因为您只需要合并值,但它应该比组合或嵌套 for 循环快~|size of list| 倍。
  • 注意!再次感谢您提供更多信息!
【解决方案3】:

这是一种天真的方式:

l = [[83,77],[103,97],[82,76],[101,95],[78,72],[97,91],[72,66],[89,83],[63,57],[78,72],[53,47],[65,59],[41,35],[50,44],[28,22],[34,28],[14,8],[16,10]]
new_l = []
contained = False
for i,subl in enumerate(l):
    mini, maxi = min(subl), max(subl)
    for subl2 in l:
        if mini in range(subl2[1],subl2[0]+1):
            mini = subl2[1]
        elif maxi in range(subl2[1],subl2[0]+1):
            maxi = subl2[0]
    if len(new_l)>1:
        for subl3 in new_l:
            contained = False
            if mini in range(subl3[0],subl3[1]+1) or maxi in range(subl2[0],subl2[1]+1):
                contained = True
                break
    if contained == True: continue
    new_l.append([mini,maxi])
print(new_l)

输出:

[[66, 89], [91, 103], [57, 65], [44, 53], [35, 41], [22, 34], [8, 16]]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-07
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-12-06
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多