如果我有一个输入字符串和一个数组:
s = "to_be_or_not_to_be"
pos = [15, 2, 8]
我试图找到引用原始pos
的数组s
的连续元素之间的最长公共前缀。我想获得以下输出:
longest = [3,1]
我获得此方法的方法是计算以下对中最长的公共前缀:
s[15:]
_be
和s[2:]
,_be_or_not_to_be
给3(_be
)s[2:]
_be_or_not_to_be
和s[8:]
,_not_to_be
给1(_
)但是,如果s
很大,那么当我执行s[x:]
之类的操作时,我不想创建多个副本。经过几个小时的搜索,我发现函数buffer仅维护输入字符串的一个副本,但我不确定在此上下文中使用它的最有效方法是什么。有关如何实现这一目标的任何建议?
答案 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
我使用islice
,izip
和xrange
,以防您谈论潜在的非常长字符串。
我也无法抗拒甚至不需要任何索引的“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