如何在python中合并重叠的字符串?

时间:2017-11-16 15:45:18

标签: python string merge biopython

我有一些字符串,

['SGALWDV', 'GALWDVP', 'ALWDVPS', 'LWDVPSP', 'WDVPSPV']

这些字符串彼此部分重叠。如果你手动重叠它们,你会得到:

SGALWDVPSPV

我想要一种方法从重叠字符串列表到python中的最终压缩字符串。我觉得这一定是一个问题,有人已经解决了,我试图避免重新发明轮子。我现在可以想象的方法要么是蛮力,要么是通过使用biopython和序列对齐来实现比我想要的更复杂。我有一些简单的短字符串,只是想以一种简单的方式正确地合并它们。

有没有人有任何关于在python中这样做的好方法的建议?谢谢!

6 个答案:

答案 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)

要确定两个字符串ab的重叠,您可以检查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