我正在寻找解决此问题的最节省内存的方法。
我有一个表示句子中部分字符串匹配的元组列表:
[(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 实现,用于将静态字典中的术语与给定的文本片段进行匹配。
编辑:由于这些元组列表的性质,应单独打印出重叠但不是独立的范围。例如,在字典中betaz
和zeta
单词,betazeta
的匹配项[(0,5),(4,8)]
。由于这些范围重叠,但没有包含在另一个范围中,因此答案应该是 [(0,5),(4,8)]
.我还修改了上面的输入数据集,以便涵盖这种情况。
谢谢!
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)]
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)]
因此,如果您相信自己的主要兴趣是空间效率,这里有一种方法可以做您想做的事情:
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
开销。 但这会占用更多内存!