【问题标题】:Collapse a list of range tuples into the overlapping ranges将范围元组列表折叠到重叠范围中
【发布时间】:2012-06-03 03:52:04
【问题描述】:

我正在寻找最节省内存的方法来解决这个问题。

我有一个表示句子中部分字符串匹配的元组列表:

[(0, 2), (1, 2), (0, 4), (2,6), (23, 2), (22, 6), (26, 2), (26, 2), (26, 2)]

每个元组的第一个值是匹配的开始位置,第二个值是长度。

这个想法是折叠列表,以便只报告最长的连续字符串匹配。在这种情况下,它将是:

[(0,4), (2,6), (22,6)]

我不想要最长的范围,比如algorithm to find longest non-overlapping sequences,但我希望所有的范围都按最长折叠。

如果您想知道,我正在使用 Aho-Corasick 的纯 Python 实现来将静态字典中的术语与给定的文本 sn-p 匹配。

编辑:由于这些元组列表的性质,重叠但不是独立的范围应单独打印出来。例如,在字典中有单词betazzetabetazeta 的匹配项是[(0,5),(4,8)]。由于这些范围重叠,但没有包含在另一个中,答案应该是[(0,5),(4,8)]。我还修改了上面的输入数据集,以便涵盖这种情况。

谢谢!

【问题讨论】:

  • 我想你会使用一个区间树,在添加时合并完全包含的区间,但是给出一个完整的工作答案比我现在能做的要多。
  • 建议的重复合并部分重叠。我认为这个问题应该只合并适当的包含(但我在猜测)。换句话说,其他答案为[(0,3),(1,4)] 给出了[(0,4)],而我猜这个问题期望返回两个范围。
  • @andrew cooke:OP 希望列表折叠,以便只保留最长的连续字符串匹配 - 所以我不明白为什么你认为这两个范围都在你的两个元组示例中。跨度>
  • 我不知道;这是一个猜测;我可能错了。在这种情况下,也许这种事情永远不会发生。我主要担心的是示例中不会发生这种情况(部分重叠)-这就是为什么我认为可能不需要它的原因。我认为您的论点没有说服力,因为英语很差,而且帖子很混乱。如果发帖人能在帖子关闭前澄清一下就好了。

标签: python tuples overlapping-matches


【解决方案1】:
import operator
lst = [(0, 2), (1, 2), (0, 4), (2,6), (23, 2), (22, 6), (26, 2), (26, 2), (26, 2)]
lst.sort(key=operator.itemgetter(1))
for i in reversed(xrange(len(lst)-1)):
    start, length = lst[i]
    for j in xrange(i+1, len(lst)):
        lstart, llength = lst[j]
        if start >= lstart and start + length <= lstart + llength:
            del lst[i]
            break
print lst
#[(0, 4), (2, 6), (22, 6)]

【讨论】:

    【解决方案2】:
    a = [(0, 2), (1, 2), (0, 4), (23, 2), (22, 6), (26, 2), (26, 2), (26, 2)]
    b = [set(xrange(i, i + j)) for i, j in a]
    c = b.pop().union(*b)
    collapsed = sorted(c)
    print collapsed
    #Maybe this is useful?:
    [0, 1, 2, 3, 22, 23, 24, 25, 26, 27]
    
    #But if you want the requested format, then do this:
    d = []
    start = collapsed[0]
    length = 0
    for val in collapsed:
        if start + length < val:
            d.append((start,length))
            start = val
            length = 0
        elif val == collapsed[-1]:
            d.append((start,length + 1))
        length += 1
    print d
    #Output:
    [(0,4), (22,6)]
    

    【讨论】:

      【解决方案3】:

      因此,请相信您的主要兴趣是空间效率,这里有一种方法可以满足您的需求:

      lst = [(0, 2), (1, 2), (0, 4), (23, 2), (22, 6), (26, 2), (26, 2), (26, 2)]
      lst.sort()
      start, length = lst.pop(0)
      i = 0
      while i < len(lst):
          x, l = lst[i]
          if start + length < x:
              lst[i] = (start, length)
              i += 1
              start, length = x, l
          else:
              length = max(length, x + l - start)
              lst.pop(i)
      lst.append((start, length))
      

      这会在原地修改列表,不会使列表变长,只使用少量变量来保持状态,并且只需要遍历列表一次

      如果您不想就地修改列表,则可以使用更快的算法 - 从列表中间弹出项目可能会很慢,尤其是在列表很长的情况下。

      一个合理的优化是保留一个您要删除的索引的列表,然后在第二遍返回并重建该列表,这样您就可以一次重建整个列表并避免@ 987654322@ 开销。但这会占用更多内存!

      【讨论】:

      • 这为[(0,3),(1,4)] 提供了[(0,5)],无论您认为应该如何处理部分重叠,这似乎都不正确。
      猜你喜欢
      • 1970-01-01
      • 2017-06-04
      • 2010-10-12
      • 2015-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-28
      • 2018-05-02
      相关资源
      最近更新 更多