こちらは シクシク素数列 Advent Calendar 2018 の17日目の記事です。
「平成最後の」が流行語になった年に、awkです。
Wikipediaによるとsince1979らしいので、来年は40周年を機にawk再評価のムーブメントが起きるやもしれません。
ルール(転載)
- 数値に4か9を含む素数をシクシク素数と呼ぶことにします
- 19とか41とか149とか。
- 標準入力として正の整数 N を与えたら N 番目までのシクシク素数を半角カンマ区切りで標準出力してください
- 例 N = 9 の場合、 19,29,41,43,47,59,79,89,97
- N は最大で 100 とします
実装
awk '{for(i=9;$0;i++)if(match(i,/4|9/)){for(j=2;j<i;j++)if(i%j<1)j=i;printf(i<j?x:--$0?i",":i RS)}}'
懺悔
文系出身の万年素人が、ワンライナーをキメる仙人たちに憧れて、
何とか1バイトでも短く書きたい、という煩悩を最優先してシクシクHackしましたが、
これが精一杯でした。
雑な説明
awkは入力を行ごとに処理します。$0
にその行の内容が入ります。
今回の場合、正の整数 N が入ることになります。
forループの中で、シクシク素数を見つけたらそれを出力しつつ$0
を減らしていきます。
ループの繰り返し条件に$0
とあるのは、
awkでは真偽判定の文脈ではゼロは偽(ゼロ以外は真)であることを利用しています。
match関数でシクシクかどうかを見ています。
この文脈ではi
は文字列として扱われます。
内側のループで素数かどうかを見ています。
割り切って抜けた時はx
を出力。
といっても何も代入していないので、この文脈では空文字です。
最後まで割り切れなかった時にi
を叫ぶのですが、
カウントダウンしている$0
がゼロでない間はカンマをつけます。
文字列を連結するには、ただ並べて書くだけ、というこの大らかさ。
ゼロになったら、カンマの代わりに\n
とするのですが、
awkの組み込み変数RS
の初期値が改行コードであることを利用したのは、
前述の煩悩のなせるわざ。
結果
$ seq 10 | awk '{for(i=9;$0;i++)if(match(i,/4|9/)){for(j=2;j<i;j++)if(i%j<1)j=i;printf(i<j?x:--$0?i",":i RS)}}'
19
19,29
19,29,41
19,29,41,43
19,29,41,43,47
19,29,41,43,47,59
19,29,41,43,47,59,79
19,29,41,43,47,59,79,89
19,29,41,43,47,59,79,89,97
19,29,41,43,47,59,79,89,97,109
それっぽく出てると思います。
###おまけ
$ seq 4 9 | awk '{for(c=4+9;$(sick*sick);c++)if(match(c,/4|9/)){for(q=sqrt(49)-sqrt(4)-sqrt(9);c>q;q++)if(c%q<49/49)q=c;printf(c<q?sick:--$(sick*sick)?c",":q RS)}}'
19,29,41,43
19,29,41,43,47
19,29,41,43,47,59
19,29,41,43,47,59,79
19,29,41,43,47,59,79,89
19,29,41,43,47,59,79,89,97