对于Array.prototype.reduce()函数我认为是es6给数组增加的最最牛逼的方法,总会在一些复杂逻辑中你会想到它可以帮你解决问题,但总是就差那么一点点感觉写不出来或者不能一下写出来。然后就呼救大佬,大佬来了简单施展一下五年功力轻松搞定,你一看就就就是他,想拧大腿一样的后悔就差一点了,诶呀下次遇见必须搞出来。我来分享一下100个我使用了reduce()函数的场景,培养一下感觉。
1. IP段处理
首先我拿到的数据是这样子的,一个对象数组,每个对象内部是起始IP,结束IP以及这段Ip当中可用的范围。
[
{
"id": "513",
"name": "test",
"startIp": "10.19.144.100",
"endIp": "10.19.144.200",
"netmask": "255.255.255.0",
"gateway": "10.19.144.1",
"usable": 100,
"total": 101,
"usableFields": [
"10.19.144.100",
"10.19.144.102-10.19.144.200"
]
},
{
"id": "533",
"name": "test2",
"startIp": "10.19.120.100",
"endIp": "10.19.120.101",
"netmask": "255.255.255.0",
"gateway": "10.19.120.1",
"usable": 1,
"total": 2,
"usableFields": [
"10.19.120.100"
]
},
{
"id": "574",
"name": "test3",
"startIp": "10.19.130.100",
"endIp": "10.19.130.120",
"netmask": "255.255.255.0",
"gateway": "10.19.130.1",
"usable": 21,
"total": 21,
"usableFields": [
"10.19.130.100-10.19.130.120"
]
},
]
那我需要做成的效果如图,一个级联效果,那级联的数据结构我肯定是清楚的,看一眼就知道较难处理的主要是子级里面要展示的所有可用IP,数据中只返回了可用的IP范围。
如果是你第一想法是用什么做?我当时的第一想法是可定得用函数式编程了,上recude()分分钟解决了,那下面看我操作。
initIpCascData() {
this.ipCascData = ipList.map((x) => ({
label: `网段名称${x.startIp}/${x.endIp}.split('.')[3]`,
value: x.id,
children: [...x.usableFields.reduce((p, c) => { p.concat(this.formatIpData(c)) }, [])],
}))
}
// 返回可用Ip段
formatIpData(str) {
const usableIps = [];
if (str.includes('-')) {
const result = str.split('-');
const start = this.ipToNum(result[0]); // 将起始ip转为数字遍历时方便
const end = this.ipToNum(result[1]);
for (let i = start; i <= end; i++) {
// 添加对象时再转会成ip
const tempObj = { label: this.numToIp(i), value: this.numToIp(i) };
usableIps.push(tempObj);
}
} else {
// 仅有一条可用
usableIps.push({ label: str, value: str });
}
return usableIps;
},
调用formatIpData()方法,接收一个IP范围,返回一个数组是这个范围的全部IP值。usableFields中可能会有多个IP范围,通过reduce记录的p,再加上concat就可以将所有结果拼在一起,不得不说reduce()牛逼。
2. 遍历对象数组中某一数组属性,生成新的对象数组。
标题有点绕,看下数据结构就知知道了。后端返回一个对象数组,每个对象中有一个属性processList
,累计processList
中元素的加合。
// 传入的数据结构
const arr1 = [
{
processList: [
{ id: '100000', processId: '1016', processName: '设备激活调试' },
{ id: '100000', processId: '1008', processName: '混泥土浇筑' },
{ id: '100000', processId: '1012', processName: '机箱安装' },
],
},
{
processList: [
{ id: '100002' ,processId: '1016', processName: '设备激活调试' },
{ id: '100002', processId: '1008', processName: '混泥土浇筑' },
{ id: '100002', processId: '1012', processName: '机箱安装' },
{ id: '100002', processId: '1014', processName: '设备安装' },
{ id: '100002', processId: 'ele_route', processName: '取电路由' },
],
},
];
// 传出的数据结构
[
{ "processId": "1016", "positionIdList": ["100000", "100002"]},
{ "processId": "1008", "positionIdList": ["100000","100002"]},
{ "processId": "1012", "positionIdList": ["100000","100002"]},
{ "processId": "1014", "positionIdList": ["100002"]},
{"processId": "ele_route", "positionIdList": ["100002"]}
]
累加,返回新数组就让我想到reduce
。每次累加时还要遍历processList
属性中,在新数组找是否存在当前processId
。时间复杂度听到的,但目前也没想到别的写法。
reduceProcess() {
return arr1.reduce((p, c) => {
c.processList.forEach((x) => {
const tempObj = p.find((y) => x.processId === y.processId);
if (tempObj) {
tempObj.count += 1;
tempObj.positionIdList.push(c.id);
} else {
p.push({
...x,
count: 1,
positionIdList: [c.id],
});
}
});
return p;
}, []);
}