根据同一列表中的下一个项目从列表中删除项目

Ken*_*nny 21 python list bioinformatics

我刚刚开始学习python,在这里我有一个蛋白质序列的排序列表(总共59,000个序列),其中一些重叠.我在这里制作了一个玩具清单,例如:

ABCDE
ABCDEFG
ABCDEFGH
ABCDEFGHIJKLMNO
CEST
DBTSFDE
DBTSFDEO
EOEUDNBNUW
EOEUDNBNUWD
EAEUDNBNUW
FEOEUDNBNUW
FG
FGH
Run Code Online (Sandbox Code Playgroud)

我想删除那些较短的重叠并保持最长的重叠,以便所需的输出看起来像这样:

ABCDEFGHIJKLMNO
CEST
DBTSFDEO
EAEUDNBNUW
FEOEUDNBNUWD
FGH
Run Code Online (Sandbox Code Playgroud)

我该怎么做?我的代码看起来像这样:

with open('toy.txt' ,'r') as f:
    pattern = f.read().splitlines()
    print pattern

    for i in range(0, len(pattern)):
        if pattern[i] in pattern[i+1]:
            pattern.remove(pattern[i])
        print pattern
Run Code Online (Sandbox Code Playgroud)

我收到了错误消息:

['ABCDE', 'ABCDEFG', 'ABCDEFGH', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDE', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGH', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDE', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDE', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDE', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FG', 'FGH']
['ABCDEFG', 'ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FGH']
Traceback (most recent call last):
  File "test.py", line 8, in <module>
    if pattern[i] in pattern[i+1]:
IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)

sch*_*tte 15

还有其他可行的答案,但没有一个能解释你的实际问题.你真的非常接近有效的解决方案,在我看来,这是最可读的答案.

错误来自于您在检查索引时使用的同一个列表进行了变更range().

因此,在增加i变量的同时,您从列表中删除项目,这一点index error不可避免地导致了这一点.

因此,这是您的初始代码的工作版本,并进行了一些更改,

pattern = ["ABCDE","ABCDEFG","ABCDEFGH","ABCDEFGHIJKLMNO","CEST","DBTSFDE","DBTSFDEO","EOEUDNBNUW","EAEUDNBNUW","FG","FGH"]
output_pattern = []


for i in range(0, (len(pattern)-1)):
    if not pattern[i] in pattern[i+1]:
        output_pattern.append(pattern[i]) 

# Adding the last item
output_pattern.append(pattern[-1])   
print (output_pattern)

>>>> ['ABCDEFGHIJKLMNO', 'CEST', 'DBTSFDEO', 'EOEUDNBNUW', 'EAEUDNBNUW', 'FGH']    
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的列表先前已按照评论部分中的说明进行排序,则此代码将起作用.

这段代码在做什么?

基本上,它使用与初始答案相同的逻辑,它在列表上进行迭代并检查下一个项目是否包含当前项目.但是,使用另一个列表并迭代直到前一个项目,将修复您的索引问题.但是现在出现了一个问题,

我该怎么处理最后一项?

由于列表已排序,您可以将最后一项视为始终唯一.这就是我使用的原因

output_pattern.append(pattern[-1])
Run Code Online (Sandbox Code Playgroud)

这会添加初始列表的最后一项.

重要的提示

这个答案是针对OP的初始问题而写的,他希望保持较长的重叠,并根据同一列表中的下一个项目引用.如@Chris_Rands所述,如果您的顾虑与生物任务有关并需要找到任何重叠,则此解决方案不适合您的需求.

此代码无法识别潜在重叠的示例,

pattern = ["ACD", "AD", "BACD"]
Run Code Online (Sandbox Code Playgroud)

它会输出相同的结果而不删除可能的"ACD"重叠.现在,作为一个澄清,这意味着一个更复杂的算法,我最初认为这超出了问题的要求范围.如果这是你的情况,我可能在这里完全错了,但我真的认为C++实现似乎更合适.看一下@Chris_Rands在评论部分提出的CD-Hit算法.

  • @Chris_Rands我理解你的担忧.我将为未来的用户添加一个注释. (2认同)

Mar*_*ans 5

你可以在这里使用groupby()max()帮助:

from itertools import groupby

with open('toy.txt') as f_input:
    for key, group in groupby(f_input, lambda x: x[:2]):
        print(max(group, key=lambda x: len(x)).strip())
Run Code Online (Sandbox Code Playgroud)

这将显示:

ABCDEFGHIJKLMNO
CEST
DBTSFDEO
EOEUDNBNUW
EAEUDNBNUW
FGH
Run Code Online (Sandbox Code Playgroud)

groupby()通过返回基于函数的匹配项列表来工作,在这种情况下,连续的行具有相同的前2个字符.max()然后,该函数获取此列表并返回长度最长的列表项.

  • 他们不想仅仅对前2个字符进行分组,他们希望根据包含另一个字符的一个字符串进行分组 (2认同)