reduce()定义
reduce() 方法接收一个函数作为累加器,数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
⚠️ reduce() 对于空数组是不会执行回调函数的。
const arr1 = [];
arr1.reduce((prev, cur, index) => {
console.log(cur);
});
const arr2 = [1, 2, 3];
arr2.reduce((prev, cur, index) => {
console.log(cur);
});
reduce()语法
array.reduce(function(previousValue, currentValue, currentIndex, arr), initialValue)
参数描述
-
function(previousValue,currentValue, index,arr):必需。用于执行每个数组元素的函数。
- previousValue:必需。初始值initialValue, 或者上一次调用回调后的返回值。
- currentValue:必需。当前元素。
- currentIndex:可选。当前元素的索引。
- arr:可选。当前元素所属的数组对象。
-
initialValue:可选。传递给函数的初始值。
如果没有提供 initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供 initialValue,从索引0开始。
有initialValue和无initialValue对比
// 无initialValue,索引值会从1的地方开始执行回调,跳过第一个索引
const arr1 = [1, 2, 3, 4];
arr1.reduce((prev, cur, index) => {
console.log(cur);
});
// 输出结果
// 2
// 3
// 4
// 有initialValue,从索引0开始
arr1.reduce((prev, cur, index) => {
console.log(cur);
}, 100);
// 输出结果
// 1
// 2
// 3
// 4
reduce()用法
数组求和
const sum = arr => {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
return arr.reduce((prev, cur) => {
return prev + cur;
})
};
// 测试例子
const arr = [1, 2, 3, 4, 5];
sum(arr);
// 15
数组乘积
const product = arr => {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
return arr.reduce((prev, cur) => {
return prev * cur;
})
};
// 测试例子
const arr = [1, 2, 3, 4, 5];
product(arr);
// 120
数组去重
const unique = arr => {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
return arr.reduce((prev, cur) => {
if(!prev.includes(cur)) {
prev.push(cur);
}
return prev;
}, []);
};
// 测试例子
const arr = [1, 2, 1, 3, 5, 5, 1];
unique(arr);
// [1, 2, 3, 5]
统计数组中相同元素个数
const getArrItemNUm = arr => {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
return arr.reduce((prev, cur) => {
if (!prev[cur]) {
prev[cur] = 1;
} else {
prev[cur]++
}
return prev;
}, {});
};
// 测试例子
const arr = [1, 2, 1, 3, 5, 5, 1];
getArrItemNUm(arr);
// {1: 3, 2: 1, 3: 1, 5: 2}
字符串字母个数统计
const getStrItemNUm = str => {
if (!str || !str.length) {
throw new Error("参数必须是非空字符串");
}
const arr = str.split('');
return arr.reduce((prev, cur) => {
if (!prev[cur]) {
prev[cur] = 1;
} else {
prev[cur]++
}
return prev;
}, {});
};
// 测试例子
const arr = "abdfgscacsdedfdascdsdrdscdewsa";
getStrItemNUm(arr);
// {a: 4, b: 1, c: 4, d: 8, e: 2, f: 2, g: 1, r: 1, s: 6, w: 1}
根据某个key值实现分组
示例:有一个数组是[{name: "ss1", age: 18, code: 123}, {name: "ss2", age: 19, code: 234}, {name: "ss2", age: 20, code: 123}, {name: "ss1", age: 18}],根据某个key值进行分组,比如根据code进行分组,结果是
function groupBy(filedname, arr) {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
if (!filedname) {
return arr;
}
return arr.reduce((prev, cur) => {
if(cur.hasOwnProperty(filedname)) {
prev[cur[filedname]] = prev[cur[filedname]] || [];
prev[cur[filedname]].push(cur);
}
return prev;
}, {});
}
// 测试例子
const arr = [
{name: "ss1", age: 18, code: 123},
{name: "ss2", age: 19, code: 234},
{name: "ss2", age: 20, code: 123},
{name: "ss1", age: 18}
];
groupBy("code", arr);
// 输出结果
/**
{
123: [{name: "ss1", age: 18, code: 123}, {name: "ss2", age: 20, code: 123}],
234: [{name: "ss2", age: 19, code: 234}]
}
*/
groupBy("name", arr);
// 输出结果
/**
{
ss1: [{name: "ss1", age: 18, code: 123}, {name: "ss1", age: 18}],
ss2: [{name: "ss2", age: 19, code: 234}, {name: "ss2", age: 20, code: 123}]
}
*/
实现flat
function _flat(arr, depth) {
if (!Array.isArray(arr) || !arr.length || depth <= 0) {
return arr;
}
return arr.reduce((prev, cur) => {
if(Array.isArray(cur)) {
return prev.concat(_flat(cur, depth - 1));
} else {
return prev.concat(cur);
}
}, []);
}
// 测试例子
const arr = [1, 2, 3, 4, [1, 2, 3, [1, 2, 3, [1, 2, 3]]]];
_flat(arr, 1); // [1, 2, 3, 4, 1, 2, 3, [1, 2, 3, [1, 2, 3]]]
_flat(arr, 2); // [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, [1, 2, 3]]
_flat(arr, Infinity); // [1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 3]
normalize转换为树形结构
- 例如将 [{id: 1}, {id: 2, pId: 1}, ...] 的重复数组(有重复数据)转成树形结构的数组[{id: 1, child: [{id: 2, pId: 1}]}, ...] (需要去重)
function transformToTree(arr) {
if (!Array.isArray(arr) || !arr.length) {
throw new Error("参数必须是非空数组");
}
const res = [];
const map = arr.reduce((prev, cur) => {
prev[cur.id] = cur;
return prev;
}, {});
for(let k of Object.values(map)) {
if(!k.pId) {
res.push(k);
}
if(k.pId in map) {
const parent = map[k.pId];
parent.child = parent.child || [];
parent.child.push(k)
}
}
return res;
}
// 测试例子
const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}];
transformToTree(arr);
// [{id: 1, child: [{id: 2, pId: 1, child: [{id: 3, pId: 2}]}]},{id: 4, child: [{id: 5, pId: 4}]}]
- 把 entry 转换成如下对象 var entry = { 'a.b.c.dd': 'abcdd', 'a.d.xx': 'adxx', 'a.e': 'ae' }; 要求转换成如下对象 var output = { a: { b: { c: { dd: 'abcdd' } }, d: { xx: 'adxx' }, e: 'ae' } }
function transformToJson(obj) {
const res = {};
const keys = Object.keys(obj);
for(let k of keys) {
const keyArr = k.split('.');
keyArr.reduce((prev, cur, index, arr) => {
if(index === arr.length - 1) {
prev[cur] = obj[k];
return;
}
prev[cur] = prev[cur] || {};
return prev[cur];
}, res);
}
return res;
}
// 测试例子
const entry = {
'a.b.c.dd': 'abcdd',
'a.d.xx': 'adxx',
'a.e': 'ae'
};
transformToJson(entry);
// { a: { b: { c: { dd: "abcdd" } }, d: { xx: "adxx" }, e: "ae" } }
- 上一题的反向操作 把 entry 转换成如下对象 var entry = { a: { b: { c: { dd: 'abcdd' } }, d: { xx: 'adxx' }, e: 'ae' } } 要求转换成如下对象 var output = { 'a.b.c.dd': 'abcdd', 'a.d.xx': 'adxx', 'a.e': 'ae' };
const transformFun = function (obj, tmpKey = '', res = {}, nums = 0) {
for (let k in obj) {
const item = obj[k];
if (typeof item === 'object' && item !== null && Object.keys(item).length > 0) {
if (nums !== 0) {
transformFun(item, tmpKey + '.' + k, res, nums + 1);
} else {
transformFun(item, k, res, nums + 1);
}
} else {
if (nums !== 0) {
res[tmpKey + '.' + k] = item;
} else {
res[k] = item;
}
}
}
return res;
};
var entry = {
a: {
b: {
c: {
dd: 'abcdd'
}
},
d: {
xx: 'adxx'
},
e: 'ae'
}
}
transformFun(entry)
/* {
"a.b.c.dd": "abcdd",
"a.d.xx": "adxx",
"a.e": "ae",
"f": "xxxxx",
"g": {}
} */