とあるプログラミング勉強会で、「素数をプログラミングする」という課題があり、
以前にも素数プログラムを書いたので、今回はできるだけシンプルに書いてみようと思って、1行プログラミングにトライしてみました。
作った1行素数プログラムの内容解説をブログに残しておきたいと思います。
1行素数プログラム
;[...Array(99)].map((_,i)=>[...Array(i+1)].map((_,j)=>(i+2)%(j+2)===0?i+2:null).filter(i=>i)).map((i)=>i.length===1?i[0]:null).filter(i=>i)
上記をそのまま、ブラウザのJavascriptコンソールに貼り付けると、100までの数値の中で素数のモノを配列でピックアップするようにしてあります。
もっと短く書けるかもしれませんが、利便性も含めて、今の自分で最短の素数解析プログラムです。
しかも、Javascript専用なので、他のプログラム言語には、互換性もクソもまるでありません。
でも、javascriptでのプログラミングを舐めてはいけません。
Web系であれば、Javascriptでほぼ何でもできてしまうので、ショートプログラミングは学ぶべき点が多いし、プログラミングの学習にはもってこいの教材でもあると思います。
素数とは?
そもそも、プログラミングを始める前に、素数が何かわからないけど、このブログを読みたい人のために、簡単に説明します。
素数(そすう、英: prime あるいは prime number)とは、
2 以上の自然数で、正の約数が 1 とその整数自身のみであるもののことである。
正の約数の個数が 2 である自然数と言い換えることもできる。
1 より大きい自然数で素数でないものは合成数と呼ばれる。
参考 : Wikipedia
要するにそれ以上割り切れない数値です。
カンタン解説
上記の1行プログラムを見ても、よほどJavascriptをやり込んでいる人じゃない限りは、チンプンカンプンの文字の並びに見えると思います。
実は、これ、Javascriptの基本関数を3つ使っているだけなので、その点が理解できれば、読み解くことも簡単になりますよ。
基本素数プログラム
素数を求める基本のプログラムは以下です。
まずはこれを理解します。
for(let i=2; i<=100; i++){
let flg = 0
for(let j=2; j<=i-1; j++){
if(i % j === 0){flg++;break}
}
if(flg === 0){
console.log(i)
}
}
変数iは、素数かどうかを確認する元の数値。
変数jは、iを割って、割り切れるかを確認する数値。(iよりも1つ小さい数値までが対象)
i%jで、割り算計算結果の余りを求めて0になる場合は、割り切れる数値として、変数flgに0以外の値をいれる。(上記の場合は、プラス1してます。ついでに、それ以上計算する意味がないので、breakしてfor文を抜けてます)
jのforが終了して、変数flgが0のままのものは、割り切れない数値と判定できる。
ポイント1. 連番数値の入った配列の作成
Javascriptでは、Array(100)と書くと、空の器が100個ある配列データが作られます。
これに、連番の数値を入れ込むには、次のように書きます。
[...Array(100)].map((_,i)=>i])
0から99までの数値が入った配列ができました。
素数を求める時は、1を除外した2からの数値でいいので、次のように書くといいでしょう。
[...Array(99)].map((_,i)=>i+2)
2から100までの通知が入った配列が作られます。
.mapというのは、javascriptで配列の内容を書き換える時などに便利に使える関数です。
※リファレンスページ
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map
ポイント2. .map関数への置き換え
上記のmap関数を使って、1階層目のループ文を基本プログラムで置き換えてみると次のようになります。
[...Array(98)].map((_,i) => i+2).map(i => {
for(let j=2; j<=i -1; j++){
if(i % j === 0){return null}
}
return i
}).filter(i => i !== null)
for文で書いたほうが見やすいんですが、慣れるとmap関数の方が便利に思えてきます。
(ただし、全てのfor文を.mapに置き換えるのが良いわけではありません)
for文では、割り切れる数値がある場合は、nullを返して、for文をスキップさせています。
ポイント3. filterで、nullを除外する
1ループ目のfor文を.mapに置き換えることができたので、2ループ目のfor文も、.mapに置き換えてみます。
[...Array(98)].map((_, i) =>
[...Array(i+1)].map((_, j) =>
(i+2) % (j+2) === 0 ? i+2 : null
).filter(i => i !== null)
).map((i) =>
i.length === 1 ? i[0] : null
).filter(i => i !== null)
ここで初めて出てきた、.filter()という関数を理解しましょう。
.mapと似たような構文で使えて、条件にマッチしない配列内の要素を取り除くことができる関数です。
今回は、配列内の割り切れる数値をnullに置き換えて、最後にnullを除外するようにしています。
上記まで理解できたら、もう少しシェイプアップして改行をなくせば1行プログラムの完成になります。
どの辺を削ぎ落としてシェイプアップしているか、気になる人は、冒頭の1行プログラムと比較してみてください。
(結構勉強になりますよ)
あとがき
プログラムは、短ければ良いと思われガチですが、決してそうではありません。
短すぎると、読み取りにくくなります。
良質なプログラムというのは、後で別の人がコードを見た時に、理解しやすいという事も求められるので、この辺が
プログラミングの質なのではないかと個人的に考えています。
無駄に長い、無駄の多いプログラムコードと、極限まで無駄を削ぎ落としたプログラムの中間の、理解しやすいという点をちゃんと把握したければ、より他人のプログラムコードを読んで理解して、できればレビューをすると、個人のプログラミングクオリティがアップするでしょう。
とにかく書く!しか無いんでしょうね。
0 件のコメント:
コメントを投稿