在做一些项目时,会遇到一些表格数据的处理,穿梭框等数组对象的合并和去重操作,很多时候都是用两个循环来一个一个去判断,这样其实有个弊端时间和空消耗大,又做了很多重复的计算判断!在数据量比较小的时候可能觉得耗时不长,如果数据量大的话,就会有很明显的延迟。如果使用数组对象扁平化来做去重就比较简单
接下来看需求
//数组一
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)
浏览器打印出来结果
将两个扁平化后的数组对象合并成一个数组对象allList
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))
将合并且去重后的对象重组成一个具有层级的数组对象
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)
这样就大功告成啦!
完整代码
<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>
如果实现树形控件的搜索,利用扁平化操作来查找相对应的节点也是比较方便的,接下来有时间会写对树形控件的搜索操作。