reduce()とは
Array.prototype.reduce()
配列からひとつの値を求めるときに使われる。
いろんなこと出来そう、便利そう、面白そう、、、と思ったので、理解を深めるためにメモに残す。
構文
- accumulator(前回の値)
- currentValue(現在の値)
- currentIndex(現在currentとして処理されている要素のindex)
- array(現在操作されている配列)
initialValueは第2引数で初期値がはいる。
const result = array.reduce((accumulator, currentValue, currentIndex, array) => {
return accumulator
}, initialValue)
例
arrayの数字を足し上げて、合計値を得る。
初期値(initialValue)は0とする。
const array = [0, 1, 2, 3]
const initialValue = 0
const result = array.reduce(
(accumulator, currentValue, currentIndex, array) => {
console.log(
"accumulator:",
accumulator,
"currentValue:",
currentValue,
"currentIndex:",
currentIndex,
"array:",
array
)
return accumulator + currentValue
},
initialValue
)
console.log("result:", result) //6
reduce() の返値は、最後の返値である (6) となった。
これをforで書くと。。。
const array = [0, 1, 2, 3]
let value = 0
for (let i = 0; i < array.length; i++) {
value += array[i]
}
console.log(value) //6
これをforEach()で書くと。。。
const array = [0, 1, 2, 3]
const forEachResult = array => {
let sum = 0
array.forEach(number => {
return (sum += number)
})
return sum
}
console.log("forEachResult:", forEachResult(array)) //6
forやforEach()は、「配列の要素を1つずつ処理する」というのが本来の目的であり、reduce() は「単一の値を返す」のが目的なので、reduce()を使うほうが、今回の目的「arrayの数字を足し上げて、合計値を得る」手段としては、適していると言える。
理解を深めるために色々なサンプルコードを書いてみる
sample01: オブジェクトの配列の値の合計値を出す
const initialValue = 0
const array = [{ x: 0 }, { x: 1 }, { x: 2 }, { x: 3 }]
const sample01 = array.reduce((accumulator, currentValue) => {
return accumulator + currentValue.x
}, initialValue)
console.log(sample01) //6
sample02: 配列から要素を抜き出して、好きな形のオブジェクトにする
const initialValue = {}
const array = [
{ name: "keko", age: 25 },
{ name: "taro", age: 19 },
{ name: "mai", age: 17 }
]
const sample02 = array.reduce((accumulator, currentValue) => {
accumulator[currentValue.name] = currentValue.age
return accumulator
}, initialValue)
console.log(sample02) //{keko: 25, taro: 19, mai: 17}
sample03: 配列をindex付きのオブジェクトにする
const initialValue = {}
const array = [
{ name: "keko", age: 25 },
{ name: "taro", age: 19 },
{ name: "mai", age: 17 }
]
const sample03 = array.reduce((accumulator, currentValue, index) => {
accumulator[index + 1] = currentValue
return accumulator
}, initialValue)
console.log(sample03)
// {
// 1: {name: "keko", age: 25}
// 2: {name: "taro", age: 19}
// 3: {name: "mai", age: 17}
// }
sample04: 配列を欲しい要素だけにしてオブジェクトにする
const initialValue = []
const array = [
{ name: "keko", age: 25, pref: "Ehime" },
{ name: "taro", age: 19, pref: "Ehime" },
{ name: "mai", age: 17, pref: "Osaka" }
]
const sample04 = {
...array.reduce((accumulator, currentValue) => {
const { name, age } = currentValue
accumulator.push({ name, age })
return accumulator
}, initialValue)
}
console.log(sample04)
// {
// { name: "keko", age: 25 },
// { name: "taro", age: 19 },
// { name: "mai", age: 17 }
// }
sample05: プロパティによってオブジェクトをグループ化する
const initialValue = {};
const array = [
{ name: "keko", age: 25, pref: "Ehime" },
{ name: "taro", age: 19, pref: "Ehime" },
{ name: "mai", age: 17, pref: "Osaka" }
];
const sample05 = array.reduce((accumulator, currentValue) => {
let key = currentValue.pref;
if (!accumulator[key]) {
accumulator[key] = [];
}
const { name, age } = currentValue;
accumulator[key].push({ name, age });
return accumulator;
}, initialValue);
console.log(sample05);
// {
// Ehime: [
// {name: "keko", age: 25 },
// {name: "taro", age: 19 }],
// Osaka: [
// {name: "mai", age: 17 }]
// }
sample06_1: 二次元配列を一次元配列にする(concat編)
const initialValue = []
const array = [[0, 1], [2, 3], [4, 5]]
const sample06_1 = array.reduce((accumulator, currentValue) => {
return accumulator.concat(currentValue)
}, initialValue)
console.log(sample06_1) // [0, 1, 2, 3, 4, 5]
sample06_2: 二次元配列を一次元配列にする(spred演算子編)
const initialValue = []
const array = [[0, 1], [2, 3], [4, 5]]
const sample06_2 = array.reduce((accumulator, currentValue) => {
return [...accumulator, ...currentValue]
}, initialValue)
console.log(sample06_2) // [0, 1, 2, 3, 4, 5]
sample07_01: 配列内の重複している値を除外する(someで除外編)
const initialValue = []
const array = [1, 2, 2, 3, 1, "a", "b", "b"]
const sample07_01 = array.reduce((accumulator, currentValue) => {
if (!accumulator.some(item => item === currentValue)) {
accumulator.push(currentValue)
}
return accumulator
}, initialValue)
console.log(sample07_01)
sample07_02: 配列内の重複している値を除外する(indexOfで除外編)
const initialValue = []
const array = [1, 2, 2, 3, 1, "a", "b", "b"]
const sample07_02 = array.reduce((accumulator, currentValue) => {
if (accumulator.indexOf(currentValue) === -1) {
return accumulator.push(currentValue)
}
return accumulator
}, initialValue)
console.log(sample07_02)
sample08: filter() + map() の代わりに使う
map() は入力&出力は要素数は変わらないので、配列の一部要素を除外する時、filter() を適用させる必要があり、filter() と map() でそれぞれループするが、reduce() を使えばループは一度で済む。
const initialValue = []
const array = [
{ id: 1, name: "keko", age: 25 },
{ id: 2, name: "taro", age: 19 },
{ id: 3, name: "mai", age: 17 },
{ id: 4, name: "hiro", age: 30 }
]
//未成年を除外して、idとnameを取得して配列にする
const sample08 = array.reduce((accumulator, currentValue) => {
if (currentValue.age > 20) {
const { id, name } = currentValue
accumulator.push({ id, name })
}
return accumulator
}, initialValue)
console.log(sample08)
// [
// {id: 1, name: "keko"},
// {id: 4, name: "hiro"}
// ]
//filter().map()の場合
const sample08_test = array
.filter(item => item.age > 20)
.map(item => {
const { id, name } = item;
return { id, name }
})
console.log(sample08_test)
// [
// {id: 1, name: "keko"},
// {id: 4, name: "hiro"}
// ]
sample09: 多次元配列を一次元配列にする
const array = [0, [1, 2, 3, [4, 5], [6, 7, [8, 9]]]];
const mergeArry = arr => {
const result = arr.reduce((acc, current) => {
return acc.concat(current);
}, []);
return result;
};
const hasArry = arr => arr.some(item => Array.isArray(item));
const mergeAll = arr => {
if (!hasArry(arr)) {
return arr;
}
const result = mergeArry(arr);
return mergeAll(result);
};
const sample09 = mergeAll(array);
console.log(sample09); //[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
今後もsample追加していく