在做一些项目时,会遇到一些表格数据的处理,穿梭框等数组对象的合并和去重操作,很多时候都是用两个循环来一个一个去判断,这样其实有个弊端时间和空消耗大,又做了很多重复的计算判断!在数据量比较小的时候可能觉得耗时不长,如果数据量大的话,就会有很明显的延迟。如果使用数组对象扁平化来做去重就比较简单
接下来看需求

//数组一
    var List = [{
        id: "1",
        pid: "0",
        name: "a",
        children: [{
            id: "2",
            pid: "1", name: "b",
        },
        {
            id: "3",
            pid: "1", name: "c",
        },
        {
            id: "4",
            pid: "1", name: "d",
            children: [{
                id: "5",
                pid: "4", name: "e",
            }]
        }]
    }]

    //数组二
    var List1 = [
        {
            id: "4",
            pid: "1", name: "d",
            children: [{
                id: "5",
                pid: "4", name: "e",
            }, {
                id: "6",
                pid: "4", name: "6",
            }, {
                id: "7",
                pid: "4", name: "7",
            }]
        }
    ]

需求:将上面两个数组合并成一个数组,并且不能有重复的数据

对数组对象扁平化

let list1 = extractTree(List, 'children')
let list2 = extractTree(List1, 'children')

数组扁平化操作

/**
     * @description: extractTree扁平化操作
     * @param {Array} arrs     必填
     * @param {String} childs  必填
     * @param {Array} attrArr  选填  说明:只对arrs的某一个或多个字段扁平化,例子 attrArr=['id','pid'] 
     * @return {Array} 
     */    
    //以下注释是extractTree(List, 'children') 执行时
    function extractTree(arrs, childs, attrArr) {
        let attrList = [];  //存储数组对象的key
        if (!Array.isArray(arrs) && !arrs.length) return []; //如果arrs不是数组对象则直接退出
        if (typeof childs !== 'string') return [];   //定义第二参数必须为字符串
        if (!Array.isArray(attrArr) || Array.isArray(attrArr) && !attrArr.length) {   
            attrList = Object.keys(arrs[0]);   //存储数组对象的key,这里attrList=["id","pid","name","children"]
            if(attrList.indexOf(childs)!==-1){ //如果第二参数是children
                attrList.splice(attrList.indexOf(childs), 1);  //那么就把attrList的children去掉,此时就变成attrList=["id","pid","name"]
            }
        } else {
            attrList = attrArr;
        }
        let list = []; 
        const getObj = arr=> {
            //递归操作
            //arr = arrs 
            arr.forEach(row=> {
                let obj = {};
                //attrList=["id","pid","name"]
                attrList.forEach(item => {
                    obj[item] = row[item] ? row[item] : "";
                })
                list.push(obj); 
                if (row[childs]) { //如果有children这个字段,说明有下一级
                    getObj(row[childs])//递归
                }
            })
            return list;
        }
        return getObj(arrs)
    }
    console.log(list1)
    console.log(list2)

浏览器打印出来结果

es6 将数组合并_javascript


将两个扁平化后的数组对象合并成一个数组对象allList

let allList = [...list1, ...list2]
console.log(allList)

es6 将数组合并_javascript_02


对合并的数组对象去重操作

let obj = {}
    allList = allList.reduce(function (item, next) {
        obj[next.id] ? '' : obj[next.id] = true && item.push(next);
        return item;
    }, [])
    console.log(allList);
    let alist = JSON.parse(JSON.stringify(allList))

es6 将数组合并_数组_03


将合并且去重后的对象重组成一个具有层级的数组对象

let Arrlist = makeTree(alist, "pid", 'child')
function makeTree(data, pid, child) {
        let parents = data.filter(p => p[pid] === "0");
        let children = data.filter(c => c[pid] !== "0");
        dataToTree(parents, children);
        return parents;
        function dataToTree(parents, children) {
            parents.map(p => {
                children.map((c, i) => {
                    if (c[pid] === p.id) {
                        let _children = JSON.parse(JSON.stringify(children));
                        _children.splice(i, 1);
                        dataToTree([c], _children);
                        if (p[child]) {
                            p[child].push(c);
                        } else {
                            p[child] = [c]
                        }

                    }
                })
            })
        }
    }
    console.log(Arrlist)

es6 将数组合并_es6 将数组合并_04


这样就大功告成啦!

完整代码

<script type="text/javascript">
    //数组一
    var List = [{
        id: "1",
        pid: "0",
        name: "a",
        children: [{
            id: "2",
            pid: "1", name: "b",
        },
        {
            id: "3",
            pid: "1", name: "c",
        },
        {
            id: "4",
            pid: "1", name: "d",
            children: [{
                id: "5",
                pid: "4", name: "e",
            }]
        }]
    }]

    //数组二
    var List1 = [
        {
            id: "3",
            pid: "1", name: "c",
        },
        {
            id: "4",
            pid: "1", name: "d",
            children: [{
                id: "5",
                pid: "4", name: "e",
            }, {
                id: "6",
                pid: "4", name: "6",
            }, {
                id: "7",
                pid: "4", name: "7",
            }]
        }
    ]

    /**
     * @description: extractTree扁平化操作
     * @param {Array} arrs     必填
     * @param {String} childs  必填
     * @param {Array} attrArr  选填  说明:只对arrs的某一个或多个字段扁平化,例子 attrArr=['id','pid'] 
     * @return {Array} 
     */    
    //以下注释是extractTree(List, 'children') 执行时
    function extractTree(arrs, childs, attrArr) {
        let attrList = [];  //存储数组对象的key
        if (!Array.isArray(arrs) && !arrs.length) return []; //如果arrs不是数组对象则直接退出
        if (typeof childs !== 'string') return [];   //定义第二参数必须为字符串
        if (!Array.isArray(attrArr) || Array.isArray(attrArr) && !attrArr.length) {   
            attrList = Object.keys(arrs[0]);   //存储数组对象的key,这里attrList=["id","pid","name","children"]
            if(attrList.indexOf(childs)!==-1){ //如果第二参数是children
                attrList.splice(attrList.indexOf(childs), 1);  //那么就把attrList的children去掉,此时就变成attrList=["id","pid","name"]
            }
        } else {
            attrList = attrArr;
        }
        let list = []; 
        const getObj = arr=> {
            //递归操作
            //arr = arrs 
            arr.forEach(row=> {
                let obj = {};
                //attrList=["id","pid","name"]
                attrList.forEach(item => {
                    obj[item] = row[item] ? row[item] : "";
                })
                list.push(obj); 
                if (row[childs]) { //如果有children这个字段,说明有下一级
                    getObj(row[childs])//递归
                }
            })
            return list;
        }
        return getObj(arrs)
    }
    let list1 = extractTree(List, 'children')
    let list2 = extractTree(List1, 'children')
    console.log(list1)
    console.log(list2)
    let allList = [...list1, ...list2]
    console.log(allList)
    
    //去重数组
    let obj = {}
    allList = allList.reduce(function (item, next) {
        obj[next.id] ? '' : obj[next.id] = true && item.push(next);
        return item;
    }, [])
    console.log(allList);
    let alist = JSON.parse(JSON.stringify(allList))
    //重组函数
    function makeTree(data, pid, child) {
        let parents = data.filter(p => p[pid] === "0");
        let children = data.filter(c => c[pid] !== "0");
        dataToTree(parents, children);
        return parents;
        function dataToTree(parents, children) {
            parents.map(p => {
                children.map((c, i) => {
                    if (c[pid] === p.id) {
                        let _children = JSON.parse(JSON.stringify(children));
                        _children.splice(i, 1);
                        dataToTree([c], _children);
                        if (p[child]) {
                            p[child].push(c);
                        } else {
                            p[child] = [c]
                        }

                    }
                })
            })
        }
    }
    let Arrlist = makeTree(alist, "pid", 'child')
    console.log(Arrlist)
</script>

如果实现树形控件的搜索,利用扁平化操作来查找相对应的节点也是比较方便的,接下来有时间会写对树形控件的搜索操作。