前回は1から2016までの総和を取りました。今回はもうちょっと応用していきます。
1から2016までのうち、偶数のみを取り出して総和をとる
はい。いよいよ数式では難しくなってきました。いけないことはありませんが( (1+1008)1008/22 )、わかりづらいですよね。
しかし、rangeとreduceを使うだけでは、これもまたうまく動きません。そこで今回はfilterを使います。
filterとはその名のとおり絞り込むものです。これを使うとこのように書けます。
document.write(range(1, 2016).filter(n => n % 2 === 0).reduce((a, b) => a + b, 0));
%は割った余りを求める演算子、===は両辺が等しいか比べる演算子です。つまり n % 2 === 0
は「nを2で割った余りが0かどうか」、ということです。
filterは数列を先頭から順にnに入れていき、nを2で割った余りが0である要素、つまり偶数のみを抽出します。
だから、 range(1, 2016).filter(n => n % 2 === 0)
というのは {2, 4, 6, 8, … , 2014, 2016} という数列のことです。あとは前回の復習で総和取ってるだけです。
説明された後でコードを見返すと、実にコードが言葉をそのまま表していることがわかると思います。
1から2016までのうち完全数であるものを取りだしてみる
今回は総和を取りません。
完全数とは
まず完全数とはなんぞや?という人のために説明しておきます。完全数とは、その数の約数(その数自身は除く)の総和がその数自身である数のことです。
…わかりにくいので例を挙げます。例えば6です。6の約数は1,2,3,6で、6自身を除いた和が1+2+3=6であり、完全数となっています。他にも28や496なんかがあります。 1+2+4+7+14=28, 1+2+4+8+16+31+62+124+248=496です。
というかぶっちゃけ言うと今回の答えは{6,28,496}です。意外と完全数って少ないんですよね。
完全数を明文化してみる
以上を踏まえて完全数を文章にしてみます。
完全数とは、その数未満の数のうち、その数の約数であるものの総和と等しい数のことである。
こうですね。さて、明文化までできた、filterもreduceも使える、ここまでくれば自力で書けます。やってみたい人はどうぞ。しかし、まださすがに難しいと思うので答えもすぐ下に載せておきます。
コーディング
上の文章は実はコーディングしやすいように書きました。ちょっと違和感ありませんでしたか?「その数未満の数のうち」は約数って書けばいいじゃんとか。
…まあそれはさておき。コードはこちら。
document.write(range(1, 2016).filter(n =>
n === range(1, n - 1).filter(m => n % m === 0).reduce((a, b) => a + b, 0)
));
このコード、口で説明しようとすると意外と厄介です。でも、先ほどの文章をそのままコードにしていることがわかるでしょうか?
終わりに
…そろそろ厳しくなってきました。rangeやreduceはforに意味を持たせて可読性は上げてくれるのですが、やはり限界があります。