2016-08-31 11 views
3

次の処理を行う小さなプログラムを作成しました。明らかに最適な解があるかどうか疑問に思っています。文字列のリストを文字列の別のリストと一致する位置に分割します

1)文字列の2つのリストを取ります。一般に、2番目のリストの文字列は最初のリストよりも長くなりますが、これは保証されません。

2)一致する文字列を最初のリストから削除した2番目のリストから派生した文字列のリストを返します。したがって、リストには、< = 2番目のリスト内の文字列の長さの文字列が含まれます。これまでのところ、私はこれは私が持っているものである basic outline of what should happen

:私は私が話しているかの絵の例を表示しまし以下

。それは正常に動作しているようですが、私が欠けているより洗練されたソリューションがあるかどうかだけは興味があります。ちなみに、私はこのプログラムの後半で重要な、文字列の各開始点と終了点の「位置」を把握しています。

def split_sequence(sequence = "", split_seq = "", length = 8): 
    if len(sequence) < len(split_seq): 
     return [],[] 
    split_positions = [0] 
    for pos in range(len(sequence)-len(split_seq)): 
     if sequence[pos:pos+len(split_seq)] == split_seq and pos > split_positions[-1]: 
      split_positions += [pos, pos+len(split_seq)] 
    if split_positions[-1] == 0: 
     return [sequence], [(0,len(sequence)-1)] 
    split_positions.append(len(sequence)) 
    assert len(split_positions) % 2 == 0 
    split_sequences = [sequence[split_positions[_]:split_positions[_+1]] for _ in range(0, len(split_positions),2)] 
    split_seq_positions = [(split_positions[_],split_positions[_+1]) for _ in range(0, len(split_positions),2)] 
    return_sequences = [] 
    return_positions = [] 
    for pos,seq in enumerate(split_sequences): 
     if len(seq) >= length: 
      return_sequences.append(split_sequences[pos]) 
      return_positions.append(split_seq_positions[pos]) 
    return return_sequences, return_positions 





def create_sequences_from_targets(sequence_list = [] , positions_list = [],length=8, avoid = []): 
    if avoid: 
     for avoided_seq in avoid: 
      new_sequence_list = [] 
      new_positions_list = [] 
      for pos,sequence in enumerate(sequence_list): 
       start = positions_list[pos][0] 
       seqs, positions = split_sequence(sequence = sequence, split_seq = avoided_seq, length = length) 
       new_sequence_list += seqs 
       new_positions_list += [(positions[_][0]+start,positions[_][1]+start) for _ in range(len(positions))] 
     return new_sequence_list, new_positions_list 

出力例:

In [60]: create_sequences_from_targets(sequence_list=['MPHSSLHPSIPCPRGHGAQKA', 'AEELRHIHSRYRGSYWRTVRA', 'KGLAPAEISAVCEKGNFNVA'],positions_list=[(0, 20), (66, 86), (136, 155)],avoid=['SRYRGSYW'],length=3) 
Out[60]: 
(['MPHSSLHPSIPCPRGHGAQKA', 'AEELRHIH', 'RTVRA', 'KGLAPAEISAVCEKGNFNVA'], 
[(0, 20), (66, 74), (82, 87), (136, 155)]) 
+0

'string.split()'は部分文字列区切り文字を受け入れます。あなたのアルゴリズムは、デリミタ文字列を繰り返し処理できるように見えます。 –

答えて

4

はのは、この文字列、s、および削除する文字列のリストlist1を定義してみましょう:

>>> s = 'NowIsTheTimeForAllGoodMenToComeToTheAidOfTheParty' 
>>> list1 = 'The', 'Good' 

さて、これらの文字列を削除してみましょう:

>>> import re 
>>> re.split('|'.join(list1), s) 
['NowIs', 'TimeForAll', 'MenToComeTo', 'AidOf', 'Party'] 

上記の強力な機能の1つは、list1の文字列にregex-active文字を含めることができるということです。それは望ましくないかもしれません。正規表現を使用して

>>> re.split('|'.join(re.escape(x) for x in list1), s) 
['NowIs', 'TimeForAll', 'MenToComeTo', 'AidOf', 'Party'] 
+1

あなたがそれらのように参加する前に 'list1'の項目を常に' re.escape() 'する必要があります。 –

+1

@JohnLaRooy良い点。私は正規表現を使用する人のキャラクターが好きですが、あなたは誰もがそうでないということは絶対に正しいです。回答は 're.escape'の解決策で更新されました。 – John1024

4

がコードを簡素化し、それがまたはより効率的であってもなくてもよい:ジョン・ラRooyはコメントで指摘するように、list1内の文字列はと非アクティブにすることができます。

>>> import re 
>>> sequence_list = ['MPHSSLHPSIPCPRGHGAQKA', 'AEELRHIHSRYRGSYWRTVRA', 'KGLAPAEISAVCEKGNFNVA'],positions_list=[(0, 20), (66, 86), (136, 155)] 
>>> avoid = ['SRYRGSYW'] 
>>> rex = re.compile("|".join(map(re.escape, avoid))) 

>>> [[j.span() for j in rex.finditer(i)] for i in sequence_list] 
[[], [(8, 16)], []] 

この

>>> [rex.split(i) for i in sequence_list] 
[['MPHSSLHPSIPCPRGHGAQKA'], ['AEELRHIH', 'RTVRA'], ['KGLAPAEISAVCEKGNFNVA']] 

または平坦化されたリスト

のような新しい文字列を取得します(あなたがこれらにあなたのオフセットを追加する必要があります)、このような位置を取得します
>>> [j for i in sequence_list for j in rex.split(i)] 
['MPHSSLHPSIPCPRGHGAQKA', 'AEELRHIH', 'RTVRA', 'KGLAPAEISAVCEKGNFNVA'] 
関連する問題