一、前言
在我们项目开发阶段,当后端传回来的数据不太理想或者不好直接使用的话,那么此时我们就必须对数据进行处理,这次我就遇到了一种情况,当后端返回如下格式的数据,我们要对其进行分组处理。如果我没没有很好的处理方法的话,我相信这是非常消耗时间的,如果我们有所谓的“巧方法”,那么这些问题就不会再难到我们。
二、reduce方法详解
2.1 reduce方法的定义
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduce() 可以作为一个高阶函数,用于函数的 compose。
2.2 reduce方法的使用
array.reduce(function(prev, currentValue, currentIndex, arr), initialValue)
第一个参数的回调函数又接收四个参数,分别为(初始值或计算结束后的返回值,当前元素,当前元素的索引,当前元素所属的数组对象)
第二个参数是传给函数的初始值,非必传
示例:下面运用reduce 对下面数组进行了累加,reduce方法每次都返回相加后的结果,初始值未0,最终返回6。
let arr = [0, 1, 2, 3]; let value = arr.reduce((pre, cur) => { return pre + cur; }, 0); console.log(value); // 6
三、实用案例
3.1.案例一(数据处理实例)
当我们接收到后台传回来的数据,初始数据如下,对以下数据根据班级 class 进行分班
const students = [ { name: '张三', class: 1, math: 100, language: 80, english: 60, physics: 80, chemistry: 60, }, { name: '李四', class: 1, math: 120, language: 60, english: 20, physics: 100, chemistry: 100, }, { name: '王五', class: 1, math: 140, language: 90, english: 120, physics: 60, chemistry: 60, }, { name: '苑博', class: 2, math: 140, language: 90, english: 120, physics: 60, chemistry: 60, }, { name: '文轩', class: 2, math: 110, language: 60, english: 120, physics: 30, chemistry: 30, }, { name: '聪健', class: 3, math: 110, language: 60, english: 120, physics: 30, chemistry: 30, }, { name: '烨磊', class: 3, math: 88, language: 70, english: 100, physics: 45, chemistry: 56, }, { name: '烨霖', class: 3, math: 120, language: 60, english: 100, physics: 50, chemistry: 60, }, { name: '荣轩', class: 2, math: 90, language: 160, english: 120, physics: 50, chemistry: 50, }, { name: '懿轩', class: 2, math: 100, language: 90, english: 120, physics: 90, chemistry: 90, }, { name: '擎苍', class: 2, math: 100, language: 130, english: 120, physics: 10, chemistry: 40, }, { name: '绍齐', class: 1, math: 100, language: 90, english: 120, physics: 60, chemistry: 60, }, { name: '皓轩', class: 1, math: 100, language: 120, english: 120, physics: 50, chemistry: 50, }, { name: '鹭洋', class: 1, math: 100, language: 80, english: 120, physics: 30, chemistry: 90, }, { name: '潇然', class: 2, math: 110, language: 92, english: 114, physics: 56, chemistry: 74, }, { name: '智宸', class: 1, math: 100, language: 100, english: 100, physics: 30, chemistry: 30, }, { name: '风华', class: 1, math: 110, language: 60, english: 120, physics: 80, chemistry: 79, }, { name: '雨泽', class: 1, math: 100, language: 68, english: 115, physics: 36, chemistry: 83, }, { name: '浩然', class: 2, math: 105, language: 116, english: 120, physics: 90, chemistry: 60, }, { name: '瑾瑜', class: 3, math: 110, language: 60, english: 120, physics: 99, chemistry: 98, }, ];
这时我们通过写一个函数对数据进行处理,这里我们巧妙使用了reduce数组方法
通过调用方法就可以对数据进行按班级分组,同时这种问题也可以使用for循环进行处理。
function handleData(arr) { return arr.reduce((t, v) => { // 判断当前班级是否已经创建,如果已经创建,就直接 push 新数据,如果没有创建,就使用 if (t[v.class]) { t[v.class].push(v); } else { t[v.class] = [v]; } return t; }, {}); }
打印结果如下,分为三个班级,班级里有所属该班级的所有成员
3.2.案例二(数据处理实例)
对下面的数据进行处理,最终达到 省 - 市 - 区 一层包裹一层的效果,根据pid增加到对象的父亲的child里面,使数据不在冗余。方便我们后面直接查找归属地。
const regions = [ { id: "51", name: "四川省", pid: "0", }, { id: "5101", name: "成都市", pid: "51", }, { id: "5103", name: "自贡市", pid: "51", }, { id: "5104", name: "攀枝花市", pid: "51", }, { id: "5105", name: "泸州市", pid: "51", }, { id: "5107", name: "绵阳市", pid: "51", }, { id: "510101", name: "市辖区", pid: "5101", }, { id: "510104", name: "锦江区", pid: "5101", }, { id: "510105", name: "青羊区", pid: "5101", }, { id: "510106", name: "金牛区", pid: "5101", }, { id: "510107", name: "武侯区", pid: "5101", }, { id: "510108", name: "成华区", pid: "5101", }, { id: "510112", name: "龙泉驿区", pid: "5101", }, { id: "510113", name: "青白江区", pid: "5101", }, { id: "510114", name: "新都区", pid: "5101", }, { id: "510115", name: "温江区", pid: "5101", }, { id: "510116", name: "双流区", pid: "5101", }, { id: "510117", name: "郫都区", pid: "5101", }, { id: "510118", name: "新津区", pid: "5101", }, { id: "510121", name: "金堂县", pid: "5101", }, { id: "510129", name: "大邑县", pid: "5101", }, { id: "510131", name: "蒲江县", pid: "5101", }, { id: "510181", name: "都江堰市", pid: "5101", }, { id: "510182", name: "彭州市", pid: "5101", }, { id: "510183", name: "邛崃市", pid: "5101", }, { id: "510184", name: "崇州市", pid: "5101", }, { id: "510185", name: "简阳市", pid: "5101", }, { id: "510301", name: "市辖区", pid: "5103", }, { id: "510302", name: "自流井区", pid: "5103", }, { id: "510303", name: "贡井区", pid: "5103", }, { id: "510304", name: "大安区", pid: "5103", }, { id: "510311", name: "沿滩区", pid: "5103", }, { id: "510321", name: "荣县", pid: "5103", }, { id: "510322", name: "富顺县", pid: "5103", }, { id: "510401", name: "市辖区", pid: "5104", }, { id: "510402", name: "东区", pid: "5104", }, { id: "510403", name: "西区", pid: "5104", }, { id: "510411", name: "仁和区", pid: "5104", }, { id: "510421", name: "米易县", pid: "5104", }, { id: "510422", name: "盐边县", pid: "5104", }, { id: "510501", name: "市辖区", pid: "5105", }, { id: "510502", name: "江阳区", pid: "5105", }, { id: "510503", name: "纳溪区", pid: "5105", }, { id: "510504", name: "龙马潭区", pid: "5105", }, { id: "510521", name: "泸县", pid: "5105", }, { id: "510522", name: "合江县", pid: "5105", }, { id: "510524", name: "叙永县", pid: "5105", }, { id: "510525", name: "古蔺县", pid: "5105", }, { id: "510701", name: "市辖区", pid: "5107", }, { id: "510703", name: "涪城区", pid: "5107", }, { id: "510704", name: "游仙区", pid: "5107", }, { id: "510705", name: "安州区", pid: "5107", }, { id: "510722", name: "三台县", pid: "5107", }, { id: "510723", name: "盐亭县", pid: "5107", }, { id: "510725", name: "梓潼县", pid: "5107", }, { id: "510726", name: "北川羌族自治县", pid: "5107", }, { id: "510727", name: "平武县", pid: "5107", }, { id: "510781", name: "江油市", pid: "5107", }, ];
利用reduce方法对数据进行处理。
function handleData(arr, rootId = '0') { return arr.reduce((newArr, item) => { if (item.pid == rootId) { item.children = handleData(regions, item.id); newArr.push(item); } return newArr; }, []); } console.log(handleData(regions));
最终实现了我们想要的链式效果,将子级包裹在父级里面。使我们操作数据更简单,当我们将数据渲染到页面上使用for--in 更方便。
3.3 案例三(实现数组去重)
<script> let arr = [1, 2, 2, 3, 3, 4, 'a', null, null]; let value = arr.reduce((pre, cur) => { return pre.includes(cur) ? pre : pre.concat(cur); }, []); console.log(value); // [1, 2, 3, 4, 'a', null] </script>
3.4 案例四(统计元素在数组中出现的次数)
let arr = [1, 2, 1, 1, 2, 3, 4]; let value = arr.reduce((pre, cur) => { // 判断当前元素是否在已经统计好的对象里 if (cur in pre) { pre[cur]++; } else { pre[cur] = 1; } return pre; }, {}); console.log(value); // {1: 3, 2: 2, 3: 1, 4: 1}
3.5 案例五(二维数组转为一维数组)
<script> let arr = [ [1, 2], [3, 4], [5, 6], ]; let value = arr.reduce((pre, cur) => { return pre.concat(cur); }, []); console.log(value); // [1,2,3,4,5,6] </script>
3.6 案例六(对象的合并)
<script> let arr = [{ a: 1 }, { b: 2 }, { c: 3 }]; let value = arr.reduce((pre, cur) => { return { ...pre, ...cur }; }, {}); console.log(value); // {a: 1, b: 2, c: 3} </script>
四、小结
reduce方法可以用于数值,字符串,对象等类型的数组,并且可以根据需要编写不同的回调函数来实现不同的功能,reduce对我们处理数据有很大帮助,往往能给我们带来惊喜。
感谢大家,欢迎评论区一起讨论学习。