JavaScriptで関数型プログラミング - reduce()


はじめに

関数型プログラミングJavaScriptで勉強中です。今回はreduce()の使い方についてメモします。


関数型プログラミングを学んでいるときに↓のようなコードを見かけました。この関数はどちらも、渡された配列要素の合計を返す関数です。

//reducerを使わないsum関数
const sum = (arr) => {
    let result = 0;
    let index = 0;

    while (index < arr.length) {
        result = result + arr[index];
        index = index + 1;
    }
    return result;
}

//reducerを用いたsum関数
const sumByReducer = (arr) => {
    return arr.reduce ( 
        (accumulator, value) => {
            return accumulator + value;
        }, 0
    );
};

//どちらも結果は同じ
console.log(sum([1, 2, 3, 4, 5])); //=> 15
console.log(sumByReducer([1, 2, 3, 4, 5])); //=> 15


前者は馴染みのある手続き型による処理ですが、後者はなんだかよくわかりません。これについて調べたので解説していきます。


reduce()とは

2つ目の関数の配列arrにreduce()がついています。これはなんでしょうか。

MDNでは↓のように説明されてます。

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

MDN - Array.prototype.reduce()

この説明をコードでみるとこうなります。

const sumByReducer = (arr) => {
    return arr.reduce ( 
        //この関数がreducer関数
        (accumulator, value) => {
            // 単一の値にして返す
            return accumulator + value;
        }, 0
    );
};

//コールバックを外に出したバージョン
const reducer =  (accumulator, value) => {
    return accumulator + value;
};

const sumByReducer = (arr) => {
    return arr.reduce(reducer, 0);
};

console.log(sumByReducer([1, 2, 3, 4, 5])); //=> 15


accumulatorとかvalueとか色々渡されてますね。reduce()の引数について見ていきます。

const arr = [];
arr.reduce(
    callback( //配列内の各要素に対して実行されるコールバック関数
        accumulator, //コールバックの戻り値を累積。コールバックの一つ前の戻り値かinitialValueが入る。
        currentValue(任意), //処理中の配列の要素
        currentIndex(任意), //処理中の要素のインデックス
        array(任意) //reduce()が呼ばれた配列(ここではarr)
    ),
    initialValue(任意) // コールバックが最初に呼び出された時にaccumulatorに入る。指定しない場合は配列の最初の要素。
}
    


また、reduceは合計を出すこと以外にも使えます。

奇数の数値をもつ配列の要素をすべて偶数にする関数を作ってみます。

やりたいこと

[1, 3, 5, 7]  => [2, 4, 6, 8]
const convertToEven = (transform) => {
    return (arr) => {
        return arr.reduce( (accumulator, value) => {
            //concat()は配列や値を連結して新たな配列を返すメソッド
            return accumulator.concat(transform(value));
        //空の配列をaccumulatorの初期値として渡す
        }, []);
    };
};

const addOne = (x) => x + 1;

console.log(convertToEven(addOne)([1, 3, 5, 7]));


この関数の面白いところは関数の呼び出し方でしょう。

convertToEven(addOne)([1, 3, 5, 7]);

convertToEven(引数)(引数) という形になっていますが、

これは、convertToEven()が戻り値として関数を返しているからこのような呼び出し方になります。


今回はreduce()の使い方について簡単ではありますがまとめました。ご覧いただきありがとうございました。