さまざまな組み合わせを見つける

さまざまな組み合わせを見つける

ファイル A には遺伝子の行があります:

A、B、C、D、E
、P、Q、R
、G、D、V、K
、L、Q、X、I、U、G など。

一度に各行を取得すると、次のタイプの出力をどのように取得できますか。

最初の行の場合:

A、B、C
、B、C、D
、C、D、E

2行目の場合:

P、Q、R

3行目の場合:

G、D、V
、D、V、K

基本的に、各行から遺伝子の「トリプレット」を見つけたいのです。最初のトリプレットには最初の 3 つの遺伝子が含まれます。2 番目のトリプレットには 2 番目、3 番目、4 番目の遺伝子が含まれます。最後のトリプレットは行の最後の遺伝子で終わります。
これを手動で達成するのは大変な作業です。私はまだ Linux、Perl、または Python スクリプトを習得してこのスクリプトを作成できるまでには至っていないので、このコミュニティからの支援をいただければ幸いです。

答え1

使用方法awk:

function wprint() {
    print w[1], w[2], w[3];
}

function wshift(e) {
    w[1] = w[2]; w[2] = w[3]; w[3] = e;
}

BEGIN { FS = OFS = "," }

{
    wshift($1);
    wshift($2);
    wshift($3);
    wprint();

    for (i = 4; i <= NF; ++i) {
        wshift($i);
        wprint();
    }
}

それから:

$ awk -f script data.in
A,B,C
B,C,D
C,D,E
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G

このawkスクリプトは、3 つの要素の移動ウィンドウを使用しますw。各入力行について、ウィンドウの 3 つの要素に最初の 3 つのフィールドを入力し、これらをコンマ区切りのリスト (改行が続く) として出力します。次に、行の残りのフィールドを反復処理してウィンドウに移動し、各要素のウィンドウを出力します。

入力データのいずれかの行に2つ未満のフィールドが含まれている場合、次のような結果が表示されます。

A,,

または

A,B,

出力に。

すべての入力行に少なくとも 3 つのフィールドがあることが確実な場合 (または、そうでない行を無視する場合)、スクリプトをawk少し短くすることができます。

function wprint() {
    print w[1], w[2], w[3];
}

function wshift(e) {
    w[1] = w[2]; w[2] = w[3]; w[3] = e;
}

BEGIN { FS = OFS = "," }

{
    for (i = 1; i <= NF; ++i) {
        wshift($i);
        if (i >= 3) {
            wprint();
        }
    }
}

可変ウィンドウ サイズを使用したスクリプトの最初のバリエーションの一般化:

function wprint(i) {
    for (i = 1; i < n; ++i) {
        printf("%s%s", w[i], OFS);
    }
    print w[n]
}

function wshift(e,i) {
    for (i = 1; i < n; ++i) {
        w[i] = w[i + 1];
    }
    w[n] = e;
}

BEGIN { FS = OFS = "," }

{
    for (i = 1; i <= n; ++i) {
        wshift($i);
    }
    wprint();

    for (i = n + 1; i <= NF; ++i) {
        wshift($i);
        wprint();
    }
}

使用方法:

$ awk -v n=4 -f script data.in
A,B,C,D
B,C,D,E
P,Q,R,
G,D,V,K
L,Q,X,I
Q,X,I,U
X,I,U,G

答え2

perl

perl -F, -le 'BEGIN { $, = "," } while(@F >= 3) { print @F[0..2]; shift @F }' file

awk

awk -F, -v OFS=, 'NF>=3 { for(i=1; i<=NF-2; i++) print $i, $(i+1), $(i+2) }' file

答え3

Perl を使用すると、次のように対処できます。

perl -lne '/(?:([^,]+)(?=((?:,[^,]+){2}))(?{ print $1,$2 }))*$/' yourfile
perl -F, -lne '$,=","; print shift @F, @F[0..1] while @F >= 3' 
perl -F, -lne '$,=","; print splice @F, 0, 3, @F[1,2] while @F >= 3'

これを拡張すると、以下のように記述できます。

perl -lne '
   m/
      (?:                       # set up a do-while loop
         ([^,]+)                # first field which shall be deleted after printing
         (?=((?:,[^,]+){2}))    # lookahead and remember the next 2 fields
         (?{ print $1,$2 })     # print the first field + next 2 fields
      )*                        # loop back for more
      $                         # till we hit the end of line
   /x;
' yourfile

sed では、さまざまなコマンドを使用してこれを実行できます。

sed -e '
   /,$/!s/$/,/     # add a dummy comma at the EOL

   s/,/\n&/3;ta    # while there still are 3 elements in the line jump to label "a"
   d               # else quit processing this line any further

   :a              # main action
   P               # print the leading portion, i.e., that which is left of the first newline in the pattern space
   s/\n//          # take away the marker

   s/,/\n/;tb      # get ready to delete the first field
   :b

   D               # delete the first field, and apply the sed code all over from the beginning to what remains in the pattern space
' yourfile

Dc はこれを行うこともできます:

sed -e 's/[^,]*/[&]/g;y/,/ /' gene_data.in |
dc -e '
[q]sq                            # macro for quitting
[SM z0<a]sa                      # macro to store stack -> register "M"
[LMd SS zlk>b c]sb               # macro to put register "M" -> register "S"
[LS zlk>c]sc                     # macro to put register "S" -> stack
[n44an dn44an rdn10anr z3!>d]sd  # macro to print 1st three stack elements
[zsk lax lbx lcx ldx c]se        # macro that initializes & calls all other macros
[?z3>q lex z0=?]s?               # while loop to read in file line by line and run macro "e" on each line
l?x                              # main()
'

結果

A,B,C
B,C,D
C,D,E
D,E,F
E,F,G
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G

関連情報