RCIE-ジャンクのコード屋

主に自分のためにコーディングのTIPSを蓄積しています。

Javascript 高階関数を入門してみた map / filter / reduce / some / flatMap

高階関数とは?

  • 引数に関数を受け取る関数のこと(正確な説明だが、初めて聞くとわけがわからない)
  • 高階関数を使うと、配列を処理するときにfor文を使わなくて済む。
  • let i のようなループ用変数を使わず、const変数だけでコードが書けるのが嬉しい!!

2022年現在、高階関数が分からないと時代に取り残されそうな雰囲気なので、さっそく学習を始めることにした。

map:配列の要素を変換する(マッピングする)

【例題】

日付を表す8桁の数値(例:20210819)の配列がある。
これを、日を表す数値(例:19)に変換して配列を出力せよ。

mapを使わない書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
let output = [];
for(let i = 0, z = input.length; i < z; i++){
	const n日 = input[i] % 100;
	output.push(n日);
}
console.log(output); // [19, 20, 30, 31, 1]
mapを使う書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
const output = input.map(elem => {
	const n日 = elem % 100;
	return n日;
});
console.log(output); // [19, 20, 30, 31, 1]

filter:配列の要素を抜き出す(フィルタリングする)

【例題】

日付を表す8桁の数値(例:20210819)の配列がある。
ここから、12月の日付だけを抜き出して配列を出力せよ。

filter を使わない書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
let output = [];
for(let i = 0, z = input.length; i < z; i++){
	const n年月 = input[i] / 100 | 0; // YYYYMM
	const n月 = n年月 % 100;
	if(n月 === 12){
		output.push(input[i]);
	}
}
console.log(output); // [20211230, 20211231]
filter を使う書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
const output = input.filter(elem => {
	const n年月 = elem / 100 | 0; // YYYYMM
	const n月 = n年月 % 100;
	return n月 === 12; // 12月ならtrue
});
console.log(output); // [20211230, 20211231]

reduce:配列を集計して単一の値にする

【例題】

日付を表す8桁の数値(例:20210819)の配列がある。
日を表す数値(例:19)のうち、最大の数値を出力せよ。

reduce を使わない書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
let output = -1;
for(let i = 0, z = input.length; i < z; i++){
	const n日 = input[i] % 100;
	output = Math.max(n日, output);
}
console.log(output); // 31
reduce を使う書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
const output = input.reduce((acc, elem, i, ary) => { // 累積値・各要素・連番・配列自体
	const n日 = elem % 100;
	return Math.max(n日, acc);
}, -1); // 累積値の初期値
console.log(output); // 31
メモ

reduce内の関数は、5回実行される。return結果が次のacc(累積値)となる。
acc(累積値)・elem(各要素)・i(連番)・return結果は、以下の表のようになる。

acc(累積値) elem(各要素) i(連番) return結果
-1 20210819 0 19
19 20210820 1 20
20 20211230 2 30
30 20211231 3 31
31 20220101 4 31

some:ひとつでも該当すれば true を返す

【例題】

日付を表す8桁の数値(例:20210819)の配列がある。
配列の要素が昇順にソートされている場合は true、
昇順にソートされていない場合は false を出力せよ。

some を使わない書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
let output = true;
for(let i = 0, z = input.length; i < z; i++){
	if(i === 0){
		continue;
	}
	if(input[i-1] > input[i]){
		output = false; // 昇順ではない場合、false で処理終了
		break;
	}
}
console.log(output); // true
some を使う書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
const output = ! input.some((elem, i, ary) => { // 各要素・連番・配列自体
	if(i === 0){
		return false;
	}
	return ary[i-1] > elem; // 昇順ではない場合、true で処理終了
});
console.log(output); // true

flatMap:配列の次元を下げて連結する

【例題】

日付を表す8桁の数値(例:20210819)の配列がある。
日を表す数値(例:19)の配列を出力せよ。
ただし、10日、20日、30日の場合は、2つ重複させて出力せよ。

flatMap を使わない書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
let output = [];
for(let i = 0, z = input.length; i < z; i++){
	const n日 = input[i] % 100;
	if(n日 % 10 === 0){
		output.push(n日);
		output.push(n日);
	}else{
		output.push(n日);
	}
}
console.log(output); // [19, 20, 20, 30, 30, 31, 1]
flatMap を使う書き方
const input = [20210819, 20210820, 20211230, 20211231, 20220101];
const output = input.flatMap(elem => {
	const n日 = elem % 100;
	if(n日 % 10 === 0){
		return [n日, n日];
	}else{
		return [n日];
	}
});
console.log(output); // [19, 20, 20, 30, 30, 31, 1]