【问题标题】:Merging overlapping string sequences in a list合并列表中的重叠字符串序列
【发布时间】:2021-10-15 15:19:14
【问题描述】:

我试图弄清楚如何将列表中的重叠字符串合并在一起,例如

['aacc','accb','ccbe'] 

我会得到

['aaccbe']

以下代码适用于上面的示例,但是在以下情况下它不能为我提供所需的结果:

s = ['TGT','GTT','TTC','TCC','CCC','CCT','CCT','CTG','TGA','GAA','AAG','AGC','GCG','CGT','TGC','GCT','CTC','TCT','CTT','TTT','TTT','TTC','TCA','CAT','ATG','TGG','GGA','GAT','ATC','TCT','CTA','TAT','ATG','TGA','GAT','ATT','TTC']
a = s[0]
b = s[-1]
final_s = a[:a.index(b[0])]+b

print(final_s) 
>>>TTC

我的输出显然不正确,我不知道为什么它在这种情况下不起作用。请注意,我已经组织了列表,其中重叠的字符串彼此相邻。

【问题讨论】:

  • ['aacc', 'accb','ccbe'] 你得到['aaccbe'],你到底想做什么? Wdym“重叠”字符串?
  • 我正在尝试合并“aacc”、“accb”、“ccbe”之间的重叠。我的代码适用于这种情况,生成 aaccbe。 (去掉3个字符串的重叠部分,合并成一个新字符串)

标签: python string list bioinformatics overlap


【解决方案1】:

您可以使用 trie 存储正在运行的子字符串并更有效地确定重叠。当发生重叠的可能性时(即对于输入字符串,在 trie 中存在一个字符串,该字符串的开头或结尾是一个字母),将进行广度优先搜索以找到最大可能的重叠,然后剩余的字符串位被添加到 trie:

from collections import deque
#trie node (which stores a single letter) class definition
class Node:
   def __init__(self, e, p = None):
      self.e, self.p, self.c = e, p, []
   def add_s(self, s):
      if s:
         self.c.append(self.__class__(s[0], self).add_s(s[1:]))
      return self

class Trie:
   def __init__(self):
      self.c = []
   def last_node(self, n):
      return n if not n.c else self.last_node(n.c[0])
   def get_s(self, c, ls):
      #for an input string, find a letter in the trie that the string starts or ends with.
      for i in c:
         if i.e in ls:
            yield i
         yield from self.get_s(i.c, ls) 
   def add_string(self, s):
      q, d = deque([j for i in self.get_s(self.c, (s[0], s[-1])) for j in [(s, i, 0), (s, i, -1)]]), []
      while q:
         if (w:=q.popleft())[1] is None:
            d.append((w[0] if not w[0] else w[0][1:], w[2], w[-1]))
         elif w[0] and w[1].e == w[0][w[-1]]:
            if not w[-1]:
               if not w[1].c:
                   d.append((w[0][1:], w[1], w[-1]))
               else:
                   q.extend([(w[0][1:], i, 0) for i in w[1].c])
            else:
               q.append((w[0][:-1], w[1].p, w[1], -1))
      if not (d:={a:b for a, *b in d}):
         self.c.append(Node(s[0]).add_s(s[1:]))
      elif (m:=min(d, key=len)):
         if not d[m][-1]:
            d[m][0].add_s(m)
         else:
            t = Node(m[0]).add_s(m)
            d[m][0].p = self.last_node(t)

把它们放在一起

t = Trie()
for i in ['aacc','accb','ccbe']:
   t.add_string(i)

def overlaps(trie, c = ''):
   if not trie.c:
      yield c+trie.e
   else:
      yield from [j for k in trie.c for j in overlaps(k, c+trie.e)]

r = [j for k in t.c for j in overlaps(k)]

输出:

['aaccbe']

【讨论】:

    【解决方案2】:

    使用difflib.find_longest_match 查找重叠并适当连接,然后使用reduce 应用整个列表。

    import difflib
    from functools import reduce
    
    
    def overlap(s1, s2):
        # https://stackoverflow.com/a/14128905/4001592
        s = difflib.SequenceMatcher(None, s1, s2)
        pos_a, pos_b, size = s.find_longest_match(0, len(s1), 0, len(s2))
        return s1[:pos_a] + s2[pos_b:]
    
    
    s = ['aacc','accb','ccbe']
    
    
    result = reduce(overlap, s, "")
    print(result)
    

    输出

    aaccbe
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      • 2011-02-26
      • 2014-05-05
      • 2017-08-29
      • 2017-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多