【问题标题】:Finding range overlap between at least three ranges Python查找至少三个范围Python之间的范围重叠
【发布时间】:2014-08-28 11:36:20
【问题描述】:

我有一个元组列表,我用它来标记范围的下限和上限。例如:

[(3,10), (4,11), (2,6), (8,11), (9,11)] # 5 separate ranges.

我想找到三个或更多输入范围重叠的范围。例如上面列出的元组将返回:

[(4,6), (8,11)]

我尝试了@WolframH 提供的方法来回答这个post

但我不知道我能做什么:

  • 给我多个输出范围

  • 设置至少三个范围重叠的阈值来限定输出

【问题讨论】:

  • 第二个元组不应该是(8,11)吗?另外,范围是否总是以整数为界?
  • @Brionius 是的,应该。我现在就编辑它。
  • 我认为应该是 (9,11) range(8,11) = [8,9,10] 并且这只包含在 range(4,11) 和 range(8,11 )
  • 据我所知,从 8-9 可以看出,您从 (3,10)、(4,11) 和 (8,11) 得到重叠。然后从 9 到 10,你会得到 (4,11)、(8,11) 和 (9,11) 的重叠。这涵盖了 8、9 和 10,范围为 (8,11)。
  • 好吧,我误解了你的问题。

标签: python range overlap


【解决方案1】:

您首先必须找到范围的所有组合。然后您可以将它们转换为集合并计算交集:

import itertools


limits = [(3,10), (4,11), (2,6), (8,11), (9,11)]
ranges = [range(*lim) for lim in  limits]

results = []
for comb in itertools.combinations(ranges,3):
    intersection = set(comb[0]).intersection(comb[1])
    intersection = intersection.intersection(comb[2])
    if intersection and intersection not in results and\
       not any(map(intersection.issubset, results)):
        results = filter(lambda res: not intersection.issuperset(res),results)
        results.append(intersection)


result_limits =  [(res[0], res[-1]+1) for res in map(list,results)]

它应该给你所有的三向交叉点

【讨论】:

  • 这很接近 - 它给了我[set([4, 5]), set([8, 9]), set([9]), set([9, 10])]。需要做一些工作来合并重叠,并且存在栅栏与栅栏柱的问题。
  • 我明白你关于 3 向交叉点的观点,但实际上应该是 [set([4, 6]), set([8, 9]), set([9]), set([9, 11])] 你缺少范围的结束整数。
  • 好的,必须添加以下行:result = [(res[0], res[-1]+1) for res in map(list,results)]
  • @dnalow 这似乎工作得很好,但是当我尝试将重叠与您的列表理解结合起来时,我得到 [(4, 6), (8, 10), (9, 10), (9 , 11)] 作为输出。有没有办法进一步组合这些范围?
  • 好的,我将添加 2 行以避免子集
【解决方案2】:

当然,如果需要,您可以通过蛮力检查所有组合来解决此问题。但是,如果您需要此算法进行扩展,您可以在(伪)nlogn 中进行。从技术上讲,你可以想出一个退化的最坏情况,即 O(n**2),但是whatchagonnado。

基本上,您对范围进行排序,然后对于给定范围,您查看其紧邻以查看边界是否重叠,如果是,则您向右查看将重叠间隔标记为结果。伪代码(实际上几乎是有效的python,看看那个):

ranges.sort()

for left_range, current_range, right_range in sliding_window(ranges, 3):
  if left_range.right < current_range.left:
    continue
  while right_range.left < min(left_range.right, current_range.right):
      results.append(overlap(left_range, right_range))
      right_range = right_range.next
  #Before moving on to the next node, extend the current_range's right bound
  #to be the longer of (left_range.right, current_range.right)
  #This makes sense if you think about it.
  current_range.right = max(left_range.right, current_range.right)

merge_overlapping(results)

(你还需要在最后合并一些可能重叠的范围,这是另一个 nlogn 操作 - 尽管 n 通常会在那里小得多。我不会讨论代码,但它的方法类似于上面,涉及排序然后合并。See here for an example。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多