JavaScriptのArray.reduce()はちょっとクセがあって、今まで敬遠してたのですが、理解だけはしておこうとまとめました。
Array.reduce()とは一言で言うと、配列の要素を集めて1つのアウトプットを返す関数です。
まずは基本
const arr = ["A", "B", "C"]; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }); console.log(ret); // A - B - C
これはOKです。
次に、初期値を使った場合
const arr = ["A", "B", "C"]; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }, "START"); console.log(ret); // START - A - B - C
これもOKです。
問題は要素が1個の場合
const arr = ["A"]; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }); console.log(ret); // A
関数は前に要素がないと呼ばれません。
ただし、初期値を設定した場合は、1個目の要素の前に初期値があるので、関数は呼ばれます。
const arr = ["A"]; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }, "START"); console.log(ret); // START - A
もう一つ気をつけたいのが、要素が0個の場合。 これはランタイムエラーになります。
const arr = []; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }); console.log(ret); // ランタイムエラー
要素が0個でも初期値がある場合は、想像通り大丈夫です。そして、1個で初期値が無い場合と同様、関数は呼ばれません。
const arr = []; const ret = arr.reduce( (prev, current)=>{ return prev + ' - ' + current; }, "START"); console.log(ret); // START
使用例
以上をふまえ、配列に入ったオブジェクトを、1オブジェクト1行のテキストで出力、かつ、各行のお尻には必ず改行を入れるアウトプットは、下記のような感じになります。
const arr = [ {name:"A", id:1}, {name:"B", id:2}, {name:"C", id:3}, ]; const ret = arr.reduce( (prev, current)=>{ return prev + JSON.stringify(current) + "¥n"; }, ""); console.log(ret); // {"name":"A", "id":1} // {"name":"B", "id":2} // {"name":"C", "id":3} //
Array.reduce()の挙動を知っていればそんなもんかなって感じですが、直感的で分かりやすいかと言われるとどうかなぁって感じです…。
原因は、Array.reduce()は1つ目の要素に処理を入れることはできないのに、空初期値を使って無理やり処理を入れさせているためです。
Array.reduce()だけで済まそうと横着せず、下記のように、一旦Array.map()で前処理してから使うのが本来の使い方のような気もしますね。
const arr = [ {name:"A", id:1}, {name:"B", id:2}, {name:"C", id:3}, ]; const ret = arr.map( (v)=>{ return JSON.stringify(v) + "\n"; }).reduce( (prev, current)=>{ return prev + current; }); console.log(ret); // {"name":"A", "id":1} // {"name":"B", "id":2} // {"name":"C", "id":3} //