5

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

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

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

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

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

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

我不想要最长的范围,就像在算法中找到最长的非重叠序列一样,但我希望所有的范围都被最长的折叠。

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

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

谢谢!

4

3 回答 3

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)]
于 2012-05-29T08:54:56.417 回答
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)]
于 2012-05-28T23:41:56.463 回答
-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))

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

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

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

于 2012-05-28T23:06:01.723 回答