手写系列-对象与数组扁平化

294 阅读2分钟

数组的扁平化

原数据 var array = [[1,2,3],4,5,6,[[7]],[9,[10,[8]]]]

转化为 [ 1, 2, 3, 4, 5, 6, 7, 9, 10, 8 ]

思路: 普通递归即可实现,判断数组每一项,如果isArray继续调用自己,同时每次把最终result传递进去即可

 // 递归实现
 function flatten(arr, result = []) {
    for (let item of arr) {
        if (Array.isArray(item))
            flatten(item, result)
        else
            result.push(item)
    }
    return result
}

// reduce实现

function fla(arr) {
    return arr.reduce((prev, cur) => {
        const re = Array.isArray(cur)? fla(cur): cur
        return prev.concat(re)
    }, [])
}

对象的扁平化

原数据 const obj = { a: 1, b: [1, 2, { c: true }], c: { e: 2, f: 3 }, g: null, };

转化为

{ a: 1, 'b[0]': 1, 'b[1]': 2, 'b[2].c': true, 'c.e': 2, 'c.f': 3, g: null }

思路:

  兼容性判断-先判断是否是对象类型,不是的话直接返回

  判断是数组的情况
  
  判断是对象的情况
  
let flatten2 = (obj) => {
	let result = {};
    
    let process = (key, value) => {
    	// 首先判断是基础数据类型还是引用数据类型
        if (Object(value) !== value) {
        	// 基础数据类型
            if (key) {
            	result[key] = value;
            }
        } else if(Array.isArray(value)){
       		for (let i = 0; i< value.length; i++) {
            	process(`${key}[${i}]`, value[i])
            }
            if (value.length === 0) {
            	result[key] = [];
            }
        } else {
        	let objArr = Object.keys(value);
            objArr.forEach(item => {
            	process(key?`${key}.${item}`:`${item}`, value[item])
            });
            if (objArr.length === 0 && key) {
            	result[key] = {};
            }
        }
    }
    process('', obj)
    return result;
}

数组改tree

原结构


let jsonData = [
  { id: 1, parentId: 0, name: '一级菜单A' },
  { id: 2, parentId: 0, name: '一级菜单B' },
  { id: 3, parentId: 0, name: '一级菜单C' },
  { id: 4, parentId: 1, name: '二级菜单A-A' },
  { id: 5, parentId: 1, name: '二级菜单A-B' },
  { id: 6, parentId: 2, name: '二级菜单B-A' },
  { id: 7, parentId: 4, name: '三级菜单A-A-A' },
  { id: 8, parentId: 7, name: '四级菜单A-A-A-A' },
  { id: 9, parentId: 8, name: '五级菜单A-A-A-A-A' },
];

转化为


[
   {
      "id": 1,
      "parentId": 0,
      "name": "一级菜单A",
      "children": [
         {
            "id": 4,
            "parentId": 1,
            "name": "二级菜单A-A",
            "children": [
               {
                  "id": 7,
                  "parentId": 4,
                  "name": "三级菜单A-A-A",
                  "children": [
                     {
                        "id": 8,
                        "parentId": 7,
                        "name": "四级菜单A-A-A-A",
                        "children": [
                           {
                              "id": 9,
                              "parentId": 8,
                              "name": "五级菜单A-A-A-A-A",
                              "children": []
                           }
                        ]
                     }
                  ]
               }
            ]
         },
         {
            "id": 5,
            "parentId": 1,
            "name": "二级菜单A-B",
            "children": []
         }
      ]
   },
   {
      "id": 2,
      "parentId": 0,
      "name": "一级菜单B",
      "children": [
         {
            "id": 6,
            "parentId": 2,
            "name": "二级菜单B-A",
            "children": []
         }
      ]
   },
   {
      "id": 3,
      "parentId": 0,
      "name": "一级菜单C",
      "children": []
   }
]

实现

双层filter遍历,外层找到需要返回的id=0的跟元素,内层遍历找到外层每一个的子元素



function formatTree(obj){
    let copyedObj = JSON.parse(JSON.stringify(obj))  //深拷贝源数据
    return copyedObj.filter(parent=>{
        let findChildren = copyedObj.filter(child=>{
            return parent.id === child.parentId
        })
        findChildren.length>0 ? parent.children = findChildren :    parent.children = []
            
        return parent.parentId == 0   //返回顶层,依据实际情况判断这里的返回值
    })
 }
    
console.log(JSON.stringify(formatTree(jsonData), null, 3));