魔法JS☆あれい 第11話「最後に残ったreduceとreduceRight」


登場人物

丹生(にゅう)あれい
魔法少女「魔法(マジカル)JS(女子小学生)☆あれい」として活動中。

イテレー太
正体不明の魔法生物。

第1部「ミューテーター・メソッド編」
* 第1話「popでpushした、ような……」
* 第2話「shiftはとってもunshiftって」
* 第3話「もうsortもreverseも怖くない」
* 第4話「fillも、spliceも、copyWithinもあるんだよ」

第2部「アクセサ・メソッド編」
* 第5話「joinなんて、concatなわけない」
* 第6話「indexOfなの絶対lastIndexOf」
* 第7話「includesのsliceと向き合えますか?」

第3部「イテレーション・メソッド編」
* 第8話「filterって、ほんとfindとfindIndex」
* 第9話「someなの、everyが許さない」
* 第10話「もうmapにもforEachにも頼らない」

reduce()

イテレー太「さあ、そろそろ戦いのクライマックスだよ!」
あれい「まだあるのかこの駄犬」
イ「召喚したデータは第8話を参照してね! そして、今回の敵の弱点は、『すべての記事のLGTM(likes_count)数の合計値』だよ!」
あ「はあ……」
イ「さあ、LGTMの合計値をreturnして敵を倒してよ!」
あ「はあ……面倒くせえなあ……」

var sum = 0;
items.forEach(item => {
  sum += item.likes_count;
});
return sum;

イ「……あれい、コードのレベルの急落幅が凄まじいよ。目に余るものがあるよ」
あ「もう疲れてきたんだよ」
イ「ダメだよ! こんなコードじゃ敵を倒せないよ! 特にforEach()は前回『使いみちがよくわからない』って言っちゃってるよ!」
あ「結果だけ合ってりゃいいだろ」
イ「そんなんじゃ魔法少女じゃないよ! いつものように1行でビシッと決めてよ!」
あ「面倒くせえなあ……」

return items.reduce((sum, item) => sum += item.likes_count, 0);

あ「これでいいのか」
イ「それでこそあれいだよ! そして解説をお願い!」
あ「はあ、面倒くせえなあ……だから、reduce() メソッドですべての記事にアクセスして、likes_countの値を順にsumに加算してるんだよ。で、予めアキュムレータであるsumの初期値を0に設定している」
イ「いやー、さすがはあれい! やればできるのに最初あからさまに手を抜いたね!」
あ「うるせえ」

解説

reduce() は配列の各要素に対して(引数で与えられた)reducer 関数を実行して、単一の値にします。

MDNより)

reduce()メソッドは、配列のメソッドの中でも最もややこしいメソッドの一つです。ただし、コツさえつかめば非常に便利です。
reduce()メソッドは、「コールバック関数、アキュムレータの初期値」の2つの引数を使用できます。さらにコールバック関数では、「アキュムレータ(コールバックの戻り値を蓄積する変数)、現在の要素、現在の要素のインデックス、元の配列」という4つの引数を使用できます。
……と書くと非常にややこしいんですが、単にmap()メソッドのように「すべての要素に関数を実行」し、その結果が順にアキュムレータに蓄積されていく……と考えると、少しはわかりやすいかもしれません。
また、アキュムレータの初期値を指定しなかった場合、配列の最初の要素が使用されます。

例えば、LGTM数の最大値を算出したい場合は、次のような記述になります。

return items.reduce((max, item) => max > item.likes_count ? max : item.likes_count, 0);

reduceRight()

解説

reduceRight()は、隣り合う 2 つの配列要素に対して(右から左へ)同時に関数を適用し、単一の値にします。

MDNより)

さて、あれいも疲れているようなので、reduceRight() メソッドについては解説のみとなります。
reduce()メソッドとの違いは、「コールバック関数が最後の要素から逆順に実行される」「アキュムレータの初期値を指定しなかった場合、配列の最後の要素が使用される」の2点です。

次回予告

ネストされた配列が扱いにくいだなんて言われたら、
私、そんなのはフラット化できるって、何度でもそう言い返せます。
きっといつまでも言い張れます。

最終話 flatの、最高のflatMap