使用缓冲区的最长公共前缀?

时间:2011-11-10 00:59:35

标签: python string text buffer

如果我有一个输入字符串和一个数组:

s = "to_be_or_not_to_be" 
pos = [15, 2, 8]

我试图找到引用原始pos的数组s的连续元素之间的最长公共前缀。我想获得以下输出:

longest = [3,1]

我获得此方法的方法是计算以下对中最长的公共前缀:

  • s[15:] _bes[2:]_be_or_not_to_be给3(_be
  • s[2:] _be_or_not_to_bes[8:]_not_to_be给1(_

但是,如果s很大,那么当我执行s[x:]之类的操作时,我不想创建多个副本。经过几个小时的搜索,我发现函数buffer仅维护输入字符串的一个副本,但我不确定在此上下文中使用它的最有效方法是什么。有关如何实现这一目标的任何建议?

4 个答案:

答案 0 :(得分:2)

>>> import os
>>> os.path.commonprefix([s[i:] for i in pos])
'_'

让Python为您管理内存。不要过早优化。

要获得您可以做的确切输出(如@agf suggested):

print [len(commonprefix([buffer(s, i) for i in adj_indexes]))
       for adj_indexes in zip(pos, pos[1:])]
# -> [3, 1]

答案 1 :(得分:2)

这是一个没有buffer但没有复制的方法,因为它一次只查看一个字符:

from itertools import islice, izip

s = "to_be_or_not_to_be"
pos = [15, 2, 8]


length = len(s)    

for start1, start2 in izip(pos, islice(pos, 1, None)):
    pref = 0
    for pos1, pos2 in izip(xrange(start1, length), xrange(start2, length)):
        if s[pos1] == s[pos2]:
            pref += 1
        else:
            break
    print pref
# prints 3 1

我使用isliceizipxrange,以防您谈论潜在的非常长字符串。

我也无法抗拒甚至不需要任何索引的“One Liner”:

[next((i for i, (a, b) in 
    enumerate(izip(islice(s, start1, None), islice(s, start2, None))) 
        if a != b), 
    length - max((start1, start2))) 
 for start1, start2 in izip(pos, islice(pos, 1, None))]

最后一种方法,使用os.path.commonprefix

[len(commonprefix((buffer(s, n), buffer(s, m)))) for n, m in zip(pos, pos[1:])]

答案 2 :(得分:1)

我认为你对副本的担忧是没有根据的。见下文:

>>> s = "how long is a piece of string...?"
>>> t = s[12:]
>>> print t
a piece of string...?
>>> id(t[0])
23295440
>>> id(s[12])
23295440
>>> id(t[2:20]) == id(s[14:32])
True

除非您复制切片并留下对副本的引用,否则我认为这不会导致任何问题。


编辑:有关于字符串实习的技术细节和我自己并不清楚的东西。但我确信字符串切片不是总是副本:

>>> x = 'google.com'
>>> y = x[:]
>>> x is y
True

我想我想给出的答案就是让python自己管理它的内存,首先,如果需要,你可以查看内存缓冲区和视图。如果这已经是您遇到的真正问题,请使用实际问题的详细信息更新您的问题。

答案 3 :(得分:0)

使用buffer的一种方法如下。但是,可能有更快的方法。

s = "to_be_or_not_to_be" 
pos = [15, 2, 8]

lcp = []
length = len(pos) - 1

for index in range(0, length):
    pre = buffer(s, pos[index])
    cur = buffer(s, pos[index+1], pos[index+1]+len(pre))

    count = 0

    shorter, longer = min(pre, cur), max(pre, cur)

    for i, c in enumerate(shorter):
        if c != longer[i]:
            break
        else:
            count += 1

    lcp.append(count)
    print 

print lcp