組み合わせを生成する
投稿:2020-11-06
こちらのブログを拝見したので。
perlワンライナーでAAAAからTTTTまでの塩基配列を全部リストアップする #Perl - Qiita
シェル(Unix/Linuxのコマンドプロンプト)限定です。 しかもPerlでないときたもんだ。 「え、なんでできるの!?」と思った方が少なからずいらっしゃると思います。 私もそう思いました(笑)。
printf "%s\n" {A,C,G,T}{A,C,G,T}{A,C,G,T}{A,C,G,T}
嘘じゃねえって、ホントにこれで出るんだって!
AAAA AAAC AAAG AAAT AACA AACC AACG AACT AAGA AAGC AAGG AAGT AATA AATC AATG AATT ACAA ACAC ACAG ACAT ACCA ACCC ACCG ACCT ACGA ACGC ACGG ACGT ACTA ACTC ACTG ACTT AGAA AGAC AGAG AGAT AGCA AGCC AGCG AGCT AGGA AGGC AGGG AGGT AGTA AGTC AGTG AGTT ATAA ATAC ATAG ATAT ATCA ATCC ATCG ATCT ATGA ATGC ATGG ATGT ATTA ATTC ATTG ATTT CAAA CAAC CAAG CAAT CACA CACC CACG CACT CAGA CAGC CAGG CAGT CATA CATC CATG CATT CCAA CCAC CCAG CCAT CCCA CCCC CCCG CCCT CCGA CCGC CCGG CCGT CCTA CCTC CCTG CCTT CGAA CGAC CGAG CGAT CGCA CGCC CGCG CGCT CGGA CGGC CGGG CGGT CGTA CGTC CGTG CGTT CTAA CTAC CTAG CTAT CTCA CTCC CTCG CTCT CTGA CTGC CTGG CTGT CTTA CTTC CTTG CTTT GAAA GAAC GAAG GAAT GACA GACC GACG GACT GAGA GAGC GAGG GAGT GATA GATC GATG GATT GCAA GCAC GCAG GCAT GCCA GCCC GCCG GCCT GCGA GCGC GCGG GCGT GCTA GCTC GCTG GCTT GGAA GGAC GGAG GGAT GGCA GGCC GGCG GGCT GGGA GGGC GGGG GGGT GGTA GGTC GGTG GGTT GTAA GTAC GTAG GTAT GTCA GTCC GTCG GTCT GTGA GTGC GTGG GTGT GTTA GTTC GTTG GTTT TAAA TAAC TAAG TAAT TACA TACC TACG TACT TAGA TAGC TAGG TAGT TATA TATC TATG TATT TCAA TCAC TCAG TCAT TCCA TCCC TCCG TCCT TCGA TCGC TCGG TCGT TCTA TCTC TCTG TCTT TGAA TGAC TGAG TGAT TGCA TGCC TGCG TGCT TGGA TGGC TGGG TGGT TGTA TGTC TGTG TGTT TTAA TTAC TTAG TTAT TTCA TTCC TTCG TTCT TTGA TTGC TTGG TTGT TTTA TTTC TTTG TTTT
こちらの解説をごらんください。
シェルすげえな。
bashのブレース展開についてまとめ #Linux - Qiita
ようやくPerlで書く段になりました。 さあ、どうぞ。 で、何故シェルより短いんだ?
perl -E "say for <@{['{A,C,G,T}' x 4]}>"
この記事を書くためにシェルの展開とか調べると「シェルだと痒い所に手が届かないから何か良い物を」とPerlが作られた頃の雰囲気を感じました。 という通り、中カッコはシェルの挙動を模倣しています。 globの機能にしているのはシェルでもファイル名として展開する用途だったのでしょうか?(・_・ ) ( ・_・) その辺りは想像なんですが。
改行するsayを使いたいので-Eを使います。 -eではsayを使えません。 するとこんなコードになります。 シェバン、バージョン番号、文字コード、警告プラグマ、バッファなし指定は嘘です、付きません、私のサンプルのスニペットです(笑)。
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
say for <@{['{A,C,G,T}' x 4]}>;
perlrun - Perl インタプリタの起動方法 - perldoc.jp-e commandline 1 行のプログラムを指定するのに使用します。 -e が指定されると Perl は引数のリストからはファイル名を探しません。 複数の -e コマンドで、複数行のスクリプトを構成することができます。 通常のプログラムでセミコロンを置くところには、セミコロンを使うことに 気を付けてください。 -E commandline -e と同様に振る舞いますが、暗黙に全てのオプション機能を(main コンパイル単位で)有効にします。 feature を参照してください。
sayは改行付きprintです。
「printと同様ですが、暗黙に改行が追加されます。」
Perlの組み込み関数 say の翻訳 - perldoc.jp
引数を指定しないので$_を使いますからprint "$_\n"になります。
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
print "$_\n" for <@{['{A,C,G,T}' x 4]}>;
後ろに付けたfor修飾子でループします。
「修飾子」
「for(each)修飾子は反復子です:LISTの値それぞれ毎に文を実行します(実行中は$_がそれぞれの値のエイリアスとなります)。」
perlsyn - Perl の文法 - perldoc.jp
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for (<@{['{A,C,G,T}' x 4]}>) {
print "$_\n";
}
世の中には一々名前の付いた変数に入れる事を好む人がいるので変数に入れておきましょう。 ただし、その変数はエイリアスだということを忘れないでください。 変数を更新する操作はループの要素を更新しますし、要素がリテラルの場合はエラー停止します。 あと$itemのレキシカルスコープはforの中だけで、forを抜けると消えます。
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for my $item (<@{['{A,C,G,T}' x 4]}>) {
print "$item\n";
}
文字列を乗法演算子xで複数回コピーできます。
「乗法演算子」
「二項演算子の"x"は繰り返し演算子です。スカラコンテキストまたは左辺値が括弧で括られていない場合は、左被演算子を右被演算子に示す数だけ繰り返したもので構成される文字列を返します。」
perlop - Perl の演算子と優先順位 - perldoc.jp
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for my $item (<@{['{A,C,G,T}{A,C,G,T}{A,C,G,T}{A,C,G,T}']}>) {
print "$item\n";
}
@{[~]}は便利な記法で、文法上いきなり~を書けず@を書ける所なら「@で始まってるからセーフ」という反則技です(いや、セーフだから)。 [~]は中にある要素をリストにしてそのリファレンスを表します。 @{~}は中にあるリファレンスをデリファレンスしたリストを表します。 なので結果は~になるという訳。 例えば"@{[1 + 2]}"が"3"になるのでお試しください。
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for my $item (<'{A,C,G,T}{A,C,G,T}{A,C,G,T}{A,C,G,T}'>) {
print "$item\n";
}
<~>の~がファイルハンドル以外であればglobを呼びます。
「I/O 演算子」
「山括弧の中の文字列がファイルハンドルでもファイルハンドル名、型グロブ、 型グロブリファレンスのいずれかが入った単純スカラ変数でもなければ、 グロブを行なうファイル名のパターンと解釈され、コンテキストによってファイル名のリストか、そのリストの次のファイル名が返されます。この区別は単に構文的に行われます。<$x>は常に間接ハンドルからreadline()しますが、<$hash{key}>は常にglob()します。$xは単純スカラー変数ですが、$hash{key}は違う(ハッシュ要素)からです。<$x >(余分な空白に注意)ですらreadline($x)ではなくglob("$x ")として扱われます。」
perlop - Perl の演算子と優先順位 - perldoc.jp
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for my $item (glob('{A,C,G,T}{A,C,G,T}{A,C,G,T}{A,C,G,T}')) {
print "$item\n";
}
中カッコを4個使っているので4重ループ処理が自動で行われます。
「空でない中かっこがglobで使われている唯一のワイルドカード文字列の場合、ファイル名とはマッチングせず、可能性のある文字列が返されます。」
Perlの組み込み関数 glob の翻訳 - perldoc.jp
#!/usr/bin/env perl
use v5.26;
use utf8;
use warnings;
use strict;
use Encode::Locale;
use feature "say";
use open IO => ":utf8";
binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";
$| = 1;
for my $item ('AAAA', 'AAAC', 'AAAG','AAAT', ~ , 'TTTA', 'TTTC', 'TTTG', 'TTTT') {
print "$item\n";
}