我有一些字符串,
['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']
这些字符串彼此部分重叠。如果你手动重叠它们,你会得到:
SGALWDVPSPV
我想要一种方法从重叠字符串列表到python中的最终压缩字符串。我觉得这一定是一个问题,有人已经解决了,我试图避免重新发明轮子。我现在可以想象的方法要么是蛮力,要么是通过使用biopython和序列对齐来实现比我想要的更复杂。我有一些简单的短字符串,只是想以一种简单的方式正确地合并它们。
有没有人有任何关于在python中这样做的好方法的建议?谢谢!
答案 0 :(得分:3)
这是一个快速排序解决方案:
s = ['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']
new_s = sorted(s, key=lambda x:s[0].index(x[0]))
a = new_s[0]
b = new_s[-1]
final_s = a[:a.index(b[0])]+b
输出:
'SGALWDVPSPV'
该程序将s
按每个元素的第一个字符的索引值排序,以试图找到最大化第一个元素和所需输出之间重叠距离的字符串。
答案 1 :(得分:3)
我提出的解决方案具有更具挑战性的测试列表:
#strFrag = ['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']
strFrag = ['ALWDVPS', 'SGALWDV', 'LWDVPSP', 'WDVPSPV', 'GALWDVP', 'LWDVPSP', 'ALWDVPS']
for repeat in range(0, len(strFrag)-1):
bestMatch = [2, '', ''] #overlap score (minimum value 3), otherStr index, assembled str portion
for otherStr in strFrag[1:]:
for x in range(0,len(otherStr)):
if otherStr[x:] == strFrag[0][:len(otherStr[x:])]:
if len(otherStr)-x > bestMatch[0]:
bestMatch = [len(otherStr)-x, strFrag.index(otherStr), otherStr[:x]+strFrag[0]]
if otherStr[:-x] == strFrag[0][-len(otherStr[x:]):]:
if x > bestMatch[0]:
bestMatch = [x, strFrag.index(otherStr), strFrag[0]+otherStr[-x:]]
if bestMatch[0] > 2:
strFrag[0] = bestMatch[2]
strFrag = strFrag[:bestMatch[1]]+strFrag[bestMatch[1]+1:]
print(strFrag)
print(strFrag[0])
基本上,代码将每个字符串/片段与列表中的第一个进行比较,并找到最佳匹配(最重叠)。它逐步合并列表,合并最佳匹配并删除单个字符串。代码假定字符串/片段之间没有不可填充的间隙(否则答案可能不会导致最长的汇编。可以通过随机化起始字符串/片段来解决)。还假设不存在反向补码(具有重叠群组装的不良假设),这将导致无意义/不可匹配的字符串/片段。我已经提供了一种限制最小匹配要求(更改bestMatch [0]值)以防止错误匹配的方法。最后的假设是所有匹配都是准确的。为了在组装序列时允许灵活性允许不匹配,使问题变得更加复杂。我可以根据要求提供不匹配的组装解决方案。
答案 2 :(得分:2)
要确定两个字符串a
和b
的重叠,您可以检查b
的任何前缀是否为a
的后缀。然后,您可以在一个简单的循环中使用该检查,聚合结果并根据重叠切片列表中的下一个字符串。
lst = ['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']
def overlap(a, b):
return max(i for i in range(len(b)+1) if a.endswith(b[:i]))
res = lst[0]
for s in lst[1:]:
o = overlap(res, s)
res += s[o:]
print(res) # SGALWDVPSPV
或使用reduce
:
from functools import reduce # Python 3
print(reduce(lambda a, b: a + b[overlap(a,b):], lst))
这可能不是超级有效的,复杂度约为O(n k),n是列表中的字符串数,k是每个字符串的平均长度。通过仅测试b
的假定重叠的最后一个字符是a
的最后一个字符,可以使它更高效,从而减少生成器表达式中字符串切片和函数调用的数量:
def overlap(a, b):
return max(i for i in range(len(b)) if b[i-1] == a[-1] and a.endswith(b[:i]))
答案 3 :(得分:1)
这是我的解决方案,从OP的角度来看,它与强力接壤。它没有受到顺序的困扰(随机抽取以确认)并且列表中可能存在不匹配的元素,以及其他独立的匹配。假设重叠意味着不是一个合适的子集,而是在开始和结束时具有共同元素的独立字符串:
from collections import defaultdict
from random import choice, shuffle
def overlap(a, b):
""" get the maximum overlap of a & b plus where the overlap starts """
overlaps = []
for i in range(len(b)):
for j in range(len(a)):
if a.endswith(b[:i + 1], j):
overlaps.append((i, j))
return max(overlaps) if overlaps else (0, -1)
lst = ['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV', 'NONSEQUITUR']
shuffle(lst) # to verify order doesn't matter
overlaps = defaultdict(list)
while len(lst) > 1:
overlaps.clear()
for a in lst:
for b in lst:
if a == b:
continue
amount, start = overlap(a, b)
overlaps[amount].append((start, a, b))
maximum = max(overlaps)
if maximum == 0:
break
start, a, b = choice(overlaps[maximum]) # pick one among equals
lst.remove(a)
lst.remove(b)
lst.append(a[:start] + b)
print(*lst)
<强>输出强>
% python3 test.py
NONSEQUITUR SGALWDVPSPV
%
计算所有重叠并将最大重叠组合成单个元素,替换原始重叠,然后重新开始处理,直到我们归结为单个元素或没有重叠。
overlap()
函数非常低效且可能会得到改善,但如果这不是OP所希望的匹配类型那么无关紧要。
答案 4 :(得分:1)
一旦肽开始长到20个氨基酸cdlane's代码扼流圈和多个不正确的答案(不同的氨基酸长度)。
尝试添加和使用AA序列&#39; VPSGALWDVPS&#39;有没有&#39; D&#39;并且代码开始失败,因为N端和C端增长并且没有反映Adam Price要求的内容。输出是:&#39; SGALWDVPSGALWDVPSPV&#39;尽管努力,100%不正确。
Tbh imo只有一个100%的答案,那就是在BioPython
包中使用BLAST及其protein search page或BLAST。或者调整cdlane的代码以反映AA差距,替换和AA添加。
答案 5 :(得分:0)
清理旧线程,但今天必须自己解决。
在这种特定情况下,片段已经按顺序排列,并且每个片段重叠的量相同(在本例中为1),虽然可能不是世界上最可靠的解决方案,但以下串联操作相当简单:
lst = ['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']
reference = "SGALWDVPSPV"
string = "".join([i[0] for i in lst] + [lst[-1][1:]])
reference == string
True