将范围元组列表折叠到重叠范围中

时间:2012-05-28 21:06:24

标签: python tuples overlapping-matches

我正在寻找解决此问题的最有效内存的方法。

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

[(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实现来将静态字典中的术语与给定的文本片段进行匹配。

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

谢谢!

3 个答案:

答案 0 :(得分:4)

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)]

答案 1 :(得分:1)

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)]

答案 2 :(得分:-1)

所以,带上你的话,你的主要兴趣是空间效率,这是你想做的事情的一种方式:

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))

这会修改列表到位,永远不会使列表更长,只使用少量变量来保持状态,只需要一次通过列表

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

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