Python 高效地生成字符串的所有可能子字符串的列表
我想编写一个函数,根据子字符串的最小和最大长度,高效地返回字符串中所有可能的子字符串的列表。(字符串仅包含大写字母。) 例如,对于字符串Python 高效地生成字符串的所有可能子字符串的列表,python,c++,c,string,list,Python,C++,C,String,List,我想编写一个函数,根据子字符串的最小和最大长度,高效地返回字符串中所有可能的子字符串的列表。(字符串仅包含大写字母。) 例如,对于字符串“ThisisString”,对于最小长度=3和最大长度=4,它应该返回: ['THI', 'THIS', 'HIS', 'HISI', 'ISI', 'ISIS', 'SIS', 'SISA', 'ISA', 'ISAS', 'SAS', 'SAST', 'AST', 'ASTR', 'STR', 'STRI', 'TRI', 'TRIN', 'RIN',
“ThisisString”
,对于最小长度=3
和最大长度=4
,它应该返回:
['THI', 'THIS', 'HIS', 'HISI', 'ISI', 'ISIS', 'SIS', 'SISA', 'ISA',
'ISAS', 'SAS', 'SAST', 'AST', 'ASTR', 'STR', 'STRI', 'TRI', 'TRIN',
'RIN', 'RING', 'ING']
我正在寻找一种比当前解决方案快得多的解决方案:
import cProfile
random_english_text = \
'AHOUSEISABUILDINGTHATISMADEFORPEOPLETOLIVEINITISAPERMANENTBUILDINGTHATISMEANTTOSTAYSTANDINGITISNOTEASILYPACKEDU' \
'PANDCARRIEDAWAYLIKEATENTORMOVEDLIKEACARAVANIFPEOPLELIVEINTHESAMEHOUSEFORMORETHANASHORTSTAYTHENTHEYCALLITTHEIRHO' \
'MEBEINGWITHOUTAHOMEISCALLEDHOMELESSNESSHOUSESCOMEINMANYDIFFERENTSHAPESANDSIZESTHEYMAYBEASSMALLASJUSTONEROOMORTH' \
'EYMAYHAVEHUNDREDSOFROOMSTHEYALSOAREMADEMANYDIFFERENTSHAPESANDMAYHAVEJUSTONELEVELORSEVERALDIFFERENTLEVELSAHOUSEI' \
'SSOMETIMESJOINEDTOOTHERHOUSESATTHESIDESTOMAKEATERRACEORROWHOUSEACONNECTEDROWOFHOUSES'
def assemble_substrings(textstring, length_min, length_max):
str_len = len(textstring)
subStringList = []
idx = 0
while idx <= str_len - length_min:
max_depth = min(length_max, str_len - idx)
for i in list(range(length_min, max_depth + 1)):
subString = textstring[idx:idx + i]
subStringList.append(subString)
idx += 1
return subStringList
pr = cProfile.Profile()
pr.enable()
for i in range(0, 1000):
list_of_substrings = assemble_substrings(textstring=random_english_text, length_min=4, length_max=10)
pr.disable()
pr.print_stats(sort='cumtime')
导入cProfile
随机英文文本=\
“适用于居住的建筑物是永久性的建筑物,且不可随意堆放”\
“如果人们居住在同一所房子里,而不是居住在他们称之为他们自己的房子里,他们会像吃的或吃的一样被带走”\
“我没有所谓的房子,但有许多不同的形状和大小,它们可能只是一个小房间”\
“他们可能有上百个房间需要不同的形状,可能只有一个或几个不同的楼层”\
“SSO有时会连接到另一个位于侧气孔的房间或与房屋相连的房间”
def集合子字符串(文本字符串、最小长度、最大长度):
str_len=len(文本字符串)
子字符串列表=[]
idx=0
虽然idx为什么不简单地使用2个范围的列表理解和字符串切片
t = "SOMETEXT"
print(t)
minl = 3
maxl = 8
parts = [t[i:i+j] for i in range(len(t)-minl) for j in range(minl,maxl+1)]
print(parts)
输出:
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'METEXT', 'METEXT', 'ETE', 'ETEX',
'ETEXT', 'ETEXT', 'ETEXT', 'ETEXT', 'TEX', 'TEXT', 'TEXT', 'TEXT', 'TEXT', 'TEXT']
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'ETE', 'ETEX', 'ETEXT', 'TEX', 'TEXT']
['THI', 'HIS', 'ISI', 'SIS', 'ISA', 'SAS', 'AST', 'STR', 'TRI', 'RIN', 'ING', 'THIS', 'HISI', 'ISIS', 'SISA', 'ISAS', 'SAST', 'ASTR', 'STRI', 'TRIN', 'RING']
如果顺序不重要,您可以使用集合删除重复项-否则为顺序存储创建唯一列表:
nodupes = []
k = set()
for l in parts:
if l in k:
pass
else:
nodupes.append(l)
k.add(l)
print(nodupes)
输出:
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'METEXT', 'METEXT', 'ETE', 'ETEX',
'ETEXT', 'ETEXT', 'ETEXT', 'ETEXT', 'TEX', 'TEXT', 'TEXT', 'TEXT', 'TEXT', 'TEXT']
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'ETE', 'ETEX', 'ETEXT', 'TEX', 'TEXT']
['THI', 'HIS', 'ISI', 'SIS', 'ISA', 'SAS', 'AST', 'STR', 'TRI', 'RIN', 'ING', 'THIS', 'HISI', 'ISIS', 'SISA', 'ISAS', 'SAST', 'ASTR', 'STRI', 'TRIN', 'RING']
定时:
def doit(t,minl,maxl):
parts = [t[i:i+j] for i in range(len(t)-minl) for j in range(minl,maxl+1)]
return parts
pr = cProfile.Profile()
pr.enable()
for i in range(0, 1000):
list_of_substrings = doit(random_english_text, 4, 10)
pr.disable()
pr.print_stats(sort='cumtime')
3001函数调用只需0.597秒
排序人:累计时间
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000 0.001 0.000 0.597 0.001主管道py:10(doit)
1000 0.596 0.001 0.596 0.001 main.py:11()
1000 0.000 0.000 0.000 0.000{内置方法内置.len}
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
您的给出:4181001函数调用只需1.614秒
我不确定它实际有多快(阅读:需要进一步研究),但对我来说,它听起来像是正则表达式的任务(re
模块),我会按照以下方式执行:
import re
minlen = 3
maxlen = 4
s = 'THISISASTRING'
out = []
for i in range(minlen,maxlen+1):
p = re.compile('(?=(.{'+str(i)+'}))',re.DOTALL)
out = out+p.findall(s)
print(out)
输出:
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'METEXT', 'METEXT', 'ETE', 'ETEX',
'ETEXT', 'ETEXT', 'ETEXT', 'ETEXT', 'TEX', 'TEXT', 'TEXT', 'TEXT', 'TEXT', 'TEXT']
['SOM', 'SOME', 'SOMET', 'SOMETE', 'SOMETEX', 'SOMETEXT', 'OME', 'OMET', 'OMETE', 'OMETEX',
'OMETEXT', 'MET', 'METE', 'METEX', 'METEXT', 'ETE', 'ETEX', 'ETEXT', 'TEX', 'TEXT']
['THI', 'HIS', 'ISI', 'SIS', 'ISA', 'SAS', 'AST', 'STR', 'TRI', 'RIN', 'ING', 'THIS', 'HISI', 'ISIS', 'SISA', 'ISAS', 'SAST', 'ASTR', 'STRI', 'TRIN', 'RING']
我用bernie的回答让findall
以重叠的方式工作。我知道这个特殊的零长度断言可以利用可变长度模式,但是当我使用re.findall('(?=(..3,4})),'THISISASTRING')
时,它产生了['this','HISI','ISIS','SISA','ISAS','SAST','ASTR','STRI TRIN','RING ING']
,这不是期望的输出。因此,我为re
解决方案提供了混合,每个循环都对应特定长度的字符串。在这里,我必须承认,我在re
方面做得不够好,无法使它以单通方式工作(仅re
,没有for
),但是,也许其他用户能够完成它?您可以映射”。join()
到压缩字符串:
def func(s, min_l, max_l):
return [subl for i in range(min_l, max_l + 1)
for subl in map(''.join, zip(*[s[i:] for i in range(i)]))]
轮廓:
输出:
ncalls tottime percall cumtime percall文件名:lineno(函数)
1000 0.002 0.000 0.772 0.001无标题。py:3(func)
7000 0.014 0.000 0.014 0.000无标题。py:4()
1 0.000 0.000 0.000 0.000{方法'disable'的''lsprof.Profiler'对象}
您想用它做什么?可能有一个比包含所有选项的列表更好的数据结构。此外,我认为您有一个边缘情况的错误,当循环处于字符串的最后一个长度时,它仍然会为每个允许的长度添加字符串。我认为字符串的结尾需要作为特例处理。对于结果列表(或其他数据结构)中的所有项,我希望能够:1。检查它们是否包含在另一个列表(或其他数据结构)2中。迭代所有元素并将它们用作访问字典的键。您的问题提醒了我另一个问题的一部分,尽管我记不清具体是哪个问题。可能吧?为什么要使用列表(范围(…)
?似乎没有必要调用list()
。非常感谢您的回答!不用说,你的回答比我的要优雅得多关于速度,你的解决方案大约比我的快3倍,这已经很好了,但如果它能快很多,那就更好了:)Thx对于你的答案,刚刚检查过,你的解决方案大约比我的快3倍。不过,我还是希望能有更大幅度的加速。:)