文字列の位置を変更して出力リストを生成する

文字列の位置を変更して出力リストを生成する

私は約30長の短い文字列(DNA配列)を扱っています。私の目的によると、すべての5番目の位置は4つのDNA塩基(A、C、T、G)のうちの1つに置き換える必要があります。たとえば、入力がある場合、AAAAAAAAAAAAAA 出力は次のリストになります。

AAAAAAAAAAAAAA
AAAACAAAAAAAAA
AAAATAAAAAAAAA
AAAAGAAAAAAAAA
AAAACAAAACAAAA
AAAACAAAATAAAA
....

言い換えれば、すべての5番目の位置はA、C、T、またはGと交換され、すべての可能な配列の配列を生成します。ここで、5番目の位置はすべての可能なDNA塩基です。

forループを使用しようとしましたが、5番目の場所ごとに編集できますが、組み合わせた方法では編集できません。

例えば

echo "AAAAAAAAAAAAAAA" > one.spacer 
for i in $(seq 1 3)
  do
    for base in {a,c,t,g}
      do
       awk -v b=$base -v x=$i '{print substr ($0,1,5*x-1) b substr ($0,5*x+1,100)}' one.spacer
    done
done

出力は次のとおりです。

AAAAaAAAAAAAAAA
AAAAcAAAAAAAAAA
AAAAtAAAAAAAAAA
AAAAgAAAAAAAAAA
AAAAAAAAAaAAAAA
AAAAAAAAAcAAAAA
AAAAAAAAAtAAAAA
AAAAAAAAAgAAAAA
AAAAAAAAAAAAAAa
AAAAAAAAAAAAAAc
AAAAAAAAAAAAAAt
AAAAAAAAAAAAAAg

しかし、5番目の場所ごとに個別に編集されているのがわかります。たとえば、次を含むシーケンスのリストが必要です。

AAAAgAAAAgAAAAg
AAAAcAAAAtAAAAa

そして他のすべての組み合わせ。これがもう少し明確になることを願っています。

答え1

すべてのUnixシステムのすべてのシェルでawkを使用して実際の30文字の幅入力の場合でも、1秒以内に実行されます。

$ cat tst.awk
function mutate(old,lgth,       new,i,j) {
    for (i=5; i<=lgth; i+=5) {
        for (j=1; j<=4; j++) {
            new = substr(old,1,i-1) substr("ACTG",j,1) substr(old,i+1)
            if ( !seen[new]++ ) {
                print new
                mutate(new,lgth)
            }
        }
    }
}

{ mutate($0,length($0)) }

$ echo 'AAAAAAAAAAAAAAA' | awk -f tst.awk
AAAAAAAAAAAAAAA
AAAACAAAAAAAAAA
AAAATAAAAAAAAAA
AAAAGAAAAAAAAAA
AAAAGAAAACAAAAA
AAAAAAAAACAAAAA
AAAACAAAACAAAAA
AAAATAAAACAAAAA
AAAATAAAATAAAAA
AAAAAAAAATAAAAA
AAAACAAAATAAAAA
AAAAGAAAATAAAAA
AAAAGAAAAGAAAAA
AAAAAAAAAGAAAAA
AAAACAAAAGAAAAA
AAAATAAAAGAAAAA
AAAATAAAAGAAAAC
AAAAAAAAAGAAAAC
AAAACAAAAGAAAAC
AAAAGAAAAGAAAAC
AAAAGAAAAAAAAAC
AAAAAAAAAAAAAAC
AAAACAAAAAAAAAC
AAAATAAAAAAAAAC
AAAATAAAACAAAAC
AAAAAAAAACAAAAC
AAAACAAAACAAAAC
AAAAGAAAACAAAAC
AAAAGAAAATAAAAC
AAAAAAAAATAAAAC
AAAACAAAATAAAAC
AAAATAAAATAAAAC
AAAATAAAATAAAAT
AAAAAAAAATAAAAT
AAAACAAAATAAAAT
AAAAGAAAATAAAAT
AAAAGAAAAAAAAAT
AAAAAAAAAAAAAAT
AAAACAAAAAAAAAT
AAAATAAAAAAAAAT
AAAATAAAACAAAAT
AAAAAAAAACAAAAT
AAAACAAAACAAAAT
AAAAGAAAACAAAAT
AAAAGAAAAGAAAAT
AAAAAAAAAGAAAAT
AAAACAAAAGAAAAT
AAAATAAAAGAAAAT
AAAATAAAAGAAAAG
AAAAAAAAAGAAAAG
AAAACAAAAGAAAAG
AAAAGAAAAGAAAAG
AAAAGAAAAAAAAAG
AAAAAAAAAAAAAAG
AAAACAAAAAAAAAG
AAAATAAAAAAAAAG
AAAATAAAACAAAAG
AAAAAAAAACAAAAG
AAAACAAAACAAAAG
AAAAGAAAACAAAAG
AAAAGAAAATAAAAG
AAAAAAAAATAAAAG
AAAACAAAATAAAAG
AAAATAAAATAAAAG

答え2

これは、良いシェルコーディング慣行と見なされるものから大きく外れ、おそらく非効率的であり、大きな入力に合わせて拡張されない。ただし、簡潔にするためにksh93シェルを使用してデフォルト値を想定すると、$IFS次のことができます。

words=($(<your-file))
printf '%s\n' ${words[@]//{4}(?)?/\1{A,C,T,G}}

を使用して${var//pattern/replacement}4文字+ 1の各シーケンスを4文字に置き換え{A,C,T,G}ます。

答え3

Pythonのモジュールには、itertoolsこれらの組み合わせの問題を処理するいくつかの方法があります。

python3 - <<\eof
import itertools as it

dna = 'atcg'
step = 5

with open('yourfile') as f:
  for _ in f:
    l = _.rstrip('\n')
    w = len(l)
    I = [i for i in range(step-1,w,step)]
    for t1 in  it.product(dna,repeat=int(w/step)):
      t = list(t1)[::-1]
      print(*[
        t.pop(0) if idx in I else e
        for idx,e in enumerate(l)],sep="")
eof
  • 反復モジュールでは、積法は入力反復のデカルト積(この場合はマルチDNAシーケンス)を生成します。
  • これは、デカルト積の数に達し、入力ファイルにまだデータが含まれている場合は、決して終了せずに最初からリサイクルを開始する無限反復子に置き換えます。

関連情報