JS使用reduce()方法處理樹形結構數據
定義
reduce() 方法對數組中的每個元素執行一個由您提供的reducer函數(升序執行),將其結果匯總為單個返回值。
reduce() 與forEach()、map()、filter()這些方法一樣,也會對數組中的每一項進行遍歷,但是reduce() 可以將遍歷的前一個數組項產生的結果與當前遍歷項進行運算。
語法
array.reduce(function(prev, cur, index, array){ ... }, init);
回調函數中的參數:
- prev 必需。表示調用回調時的返回值,或者初始值 init。
- cur 必需。表示當前元素。
- index 可選。表示當前元素的索引。
- array 表示原數組。
- init 可選。初始值,作為第一次調用回調函數的第一個參數。
其中常用參數:prev 和 cur
註意:回調函數第一次執行時,prev和cur的取值有兩種情況:如果調用reduce()時提供瞭初始值init,prev取init值,cur取數組中的第一個值,此時索引從0開始;如果沒有提供初始值init,則prev取數組中的第一個值,cur取數組中的第二個值,此時索引從1開始。
實例
1. 沒有傳遞初始值init
const arr = [1, 3, 5, 7] arr.reduce(function(prev, cur, index, arr){ console.log(prev, cur, index) return prev + cur })
每次調用的參數和返回值如下表:
callback | prev | cur | index | array | return value |
---|---|---|---|---|---|
第1次 | 1 | 3 | 1 | [1, 3, 5, 7] | 4 |
第2次 | 4 | 5 | 2 | [1, 3, 5, 7] | 9 |
第3次 | 9 | 7 | 3 | [1, 3, 5, 7] | 16 |
因為沒有傳入初始值,所以索引是從1開始,callback被調用三次,開始時prev的值為數組第一項1,cur的值為3,相加之後返回值4作為下一輪回調的prev值,然後繼續下一輪的回調,直至完成後返回。
2. 傳遞初始值的情況下
const arr = [1, 3, 5, 7] arr.reduce(function(prev, cur, index, arr){ console.log(prev, cur, index) return prev + cur }, 10)
每次調用的參數和返回值如下表:
callback | prev | cur | index | array | return value |
---|---|---|---|---|---|
第1次 | 10 | 1 | 0 | [1, 3, 5, 7] | 11 |
第2次 | 11 | 3 | 1 | [1, 3, 5, 7] | 14 |
第3次 | 14 | 5 | 2 | [1, 3, 5, 7] | 19 |
第4次 | 19 | 7 | 3 | [1, 3, 5, 7] | 26 |
3. 數組去重
const arr = ['ab', 'v', 'd', 'ab', 'h', 'e', 'dc', 'e', 'e', 'f'] const newArr = arr.reduce(function(prev, cur){ !prev.includes(cur) && prev.push(cur) return prev }, []) console.log(newArr) // ["ab", "v", "d", "h", "e", "dc", "f"]
執行的步驟如下:
- 初始化一個空數組
- 第一次調用時,prev 為初始值即空數組,cur 為數組中的第一項 arr[1],然後在 prev 中查找 cur 是否已經存在,如果不存在就將該項添加到 prev 中,並 prev 返回進入下一次回調
- 第二次回調時,prev 為第一次的返回值,cur 為數組中的第二項 arr[2],然後在 prev 中查找 cur 是否已經存在,如果不存在就將該項添加到 prev 中,並 prev 返回進入下一次回調
- 最後將 prev 這個數組返回
4. 利用 reduce 對數組中的 Object 對象進行分組及合並
//從後臺獲取的對象數組,根據對象的type進行分組合並成tree樹形展示數據 const dataArr = [ { type: '治理層', name: 'hive_82', reserve: '2', id: 1 }, { type: '原始數據層', name: 'qwe', reserve: '1', id: 2 }, { type: '貼源層', name: 'mysql_exchangis', reserve: '3', id: 3 }, { type: '治理層', name: 'links_188', reserve: '1', id: 4 }, { type: '貼源層', name: 'mysql_ces', reserve: '2', id: 5 } ] const treeData = dataArr.reduce((cur, next) => { const obj = cur.find(curItem => curItem.label === next.type) if (obj) { if (obj.children.indexOf(next.id) === -1) { //去重處理 obj.children.push({ ...next, label: next.name }) } } else { const newObj = { label: next.type, children: [{ ...next, label: next.name }] } cur.push(newObj) } return cur }, []) // 合並後的結果: treeData = [ { label: '治理層', children: [ { type: '治理層', name: 'hive_82', reserve: '2', id: 1, label: 'hive_82' }, { type: '治理層', name: 'links_188', reserve: '1', id: 4, label: 'links_188' } ] }, { label: '原始數據層', children: [ { type: '原始數據層', name: 'qwe', reserve: '1', id: 2, label: 'qwe' } ] }, { label: '貼源層', children: [ { type: '貼源層', name: 'mysql_exchangis', reserve: '3', id: 3, label: 'mysql_exchangis' }, { type: '治理層', name: 'mysql_ces', reserve: '2', id: 5, label: 'mysql_ces' } ] } ]
5. 利用 reduce 處理菜單後端返回的菜單結構
需要根據 parentId 將這些數據轉換成層級結構。
方法一:
const dataArr = [ {id: '18', name: '重置密碼', parentId: '30',parentName: '用戶管理'}, {id: '13', name: '審計日志', parentId: '29', parentName: '系統管理'}, {id: '29', name: '系統管理', parentId: '0', parentName: null}, {id: '14', name: '修改', parentId: '33', parentName: '部門管理'}, {id: '2', name: '用戶列表', parentId: '30', parentName: '用戶管理'}, {id: '30', name: '用戶管理', parentId: '29', parentName: '系統管理'}, {id: '33', name: '部門管理', parentId: '0', parentName: null}, {id: '37', name: '添加用戶', parentId: '30', parentName: '用戶管理'}, {id: '6', name: '添加', parentId: '33', parentName: '部門管理'}, {id: '7',name: '刪除', parentId: '33', parentName: '部門管理'} ] //創建菜單id的映射關系 const idMapping = dataArr.reduce((prev, next, i) => { prev[next.id] = i return prev }, {}) const treeData = [] dataArr.map(el => { // 一級菜單 if (el.parentId === '0') { treeData.push(el) return } // 通過映射找到父元素 const parentEl = dataArr[idMapping[el.parentId]] // 把當前元素添加到父元素的`children`數組中 parentEl.children = [...(parentEl.children || []), el] }) console.log(treeData)
方法二:
//根據parentId創建映射關系 const result = dataArr.reduce((prev, next) => { prev[next.parentId] ? prev[next.parentId].push(next) : prev[next.parentId] = [next]; return prev; }, {}); Object.keys(result).map(key => { result[key].map((item, i) => { result[item.id] ? item.children = result[item.id] : '' }); }) this.treeData = result[0] console.log(treeData)
還可以通過遞歸的方法來實現,具體就不贅述瞭
最後生成的數據結構如下圖所示:
以上就是JS使用reduce()方法處理樹形結構數據的詳細內容,更多關於JS的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 關於reduce的介紹及用法說明
- JavaScript中reduce()的用法實例
- JavaScript數組reduce常見實例方法
- vue深度優先遍歷多層數組對象方式(相當於多棵樹、三級樹)
- JavaScript數組對象高階函數reduce的妙用詳解