JavaScript(ES6)のreduceで配列をオブジェクトに変換する

javascript – Convert Array to Object – Stack Overflowのreduceを使った配列のオブジェクト変換が良さげだったのでメモです。

reduceについてはArray.prototype.reduce() – JavaScript | MDNあたりを。アキュムレータと各配列要素を順番に処理していくかなり便利なメソッドなのですが、初期値を空のオブジェクトに指定して各要素をオブジェクトに追加していくことでオブジェクトに変換できます。

通常の配列

プリミティブを要素に持つごく普通の配列の変換です。オブジェクトに変換する場合は任意のkeyを設定する必要があります。下記の例だとreduceからindexを受け取っています。

const arr = ['a', 'b', 'c'];

const obj = arr.reduce((result, current, index) => {
    result[index] = current;
    return result;
}, {});

console.log(obj); // { '0': 'a', '1': 'b', '2': 'c' }

reduceはcallbackのあとに初期値を指定することができます。冒頭に書いたように初期値を空のオブジェクト{}にしているのがミソで、これを指定しないと初期値は最初の要素の文字列aになってしまうのでうまく動きません。

オブジェクトを要素に持つ配列

jsonを扱うときによく見かける要素がオブジェクトになっている配列です。[{1: 'a'}, {2: 'b'}, {3: 'c'}]のように各オブジェクトのキーをそのまま使いたい場合はObject.keysでオブジェクトのキーの配列が戻ってくるのでこれを利用できます。下の例では返り値である配列のままキー指定をしていますが文字列に変換可能なものは変換されるため、今回は期待どおりに動作します。(参考: JavaScriptのオブジェクトのキーに配列が使える – Qiita)

const arr = [{1: 'a'}, {2: 'b'}, {3: 'c'}];

const obj = arr.reduce((result, current) => {
    let key = Object.keys(current);
    result[key] = current[key];
    return result;
}, {});

console.log(obj); // { '1': 'a', '2': 'b', '3': 'c' }

APIを叩いて返ってきたjsonのように各オブジェクトが規則的に複数のプロパティを持っている場合は、idなどの一意のプロパティを変換後のオブジェクトのキーにしたい場面が多そうです。下は16歳以上のメンバーだけをfilterで抽出した配列に対してメンバーの名前をキーにしたオブジェクトに変換する例です。

const arr = [{
    name: 'Kotori',
    age: 16,
    unit: 'Printemps'
}, {
    name: 'Nozomi',
    age: 17,
    unit: 'lily_white'
}, {
    name: 'Maki',
    age: 15,
    unit: 'BiBi'
}];

const obj = arr
  .filter(member => member.age >= 16)
  .reduce((result, current) => {
    result[current.name] = {
        age: current.age,
        unit: current.unit
    }
    return result;
}, {});

console.log(obj);
/*
{{ Kotori: { age: 16, unit: 'Printemps' },
Nozomi: { age: 17, unit: 'lily_white' } }
*/

forループを回すよりも見やすいのもありますが、上のようにfiltermapといった配列の便利なメソッドと組み合わせやすいところが大きなメリットだと思います。