如何移除嵌套数组/对象中的空数组?
问题描述
我有一个嵌套的对象数组,每个对象包含children数组,部分children为空数组。需要遍历整个结构,删除所有空的children数组以及对应的父对象(如果它的children处理后为空)。
示例数据:
let a = [ {children: [{children: [1,2]}, {children: [5,6]}]}, {children: [{children: []}, {children: [5,6]}]}, {children: [{children: []}, {children: []}]}, {children: []} ]
尝试了以下代码,却报错:cannot read property 'children' of undefined
function removeEmpty(array){ for(var i=array.length-1;i>=0;i--){ if(array[i].children){ if(array[i].children.length){ for(var j=array[i].children.length-1;j=>0;j--){ if(array[i].children[j].children){ removeEmpty(array[i].children[j]) }else{ array[i].splice[j,1] } } if(!array[i].children.length){ array.splice(i,1) } }else{ array.splice(i,1) } } } } removeEmpty(a)
预期结果:
let expectedOutcome = [ {children: [{children: [1,2]}, {children: [5,6]}]}, {children: [{children: [5,6]}]} ]
错误原因分析
原代码存在几个明显问题:
- 循环条件错误:
j=>0是语法错误,应该写成j>=0,这会导致循环逻辑混乱,甚至访问不存在的数组索引。 - 方法调用错误:
array[i].splice[j,1]把数组方法splice当成了数组,正确写法是array[i].children.splice(j, 1)。 - 递归参数错误:
removeEmpty(array[i].children[j])传入的是单个对象,但removeEmpty的参数要求是数组,应该传入array[i].children[j].children。 - 逻辑不完整:递归处理子数组后,没有重新检查当前对象的
children是否为空,导致无法正确删除子节点全被清理后的父对象。
修复后的解决方案
方案1:原地修改原数组
这个方案直接修改输入的数组,适合不需要保留原数据的场景:
function removeEmpty(array) { // 从后往前遍历,避免删除元素导致索引错乱 for (let i = array.length - 1; i >= 0; i--) { const currentItem = array[i]; // 确保当前元素存在children且是数组 if (currentItem.children && Array.isArray(currentItem.children)) { // 递归清理子children数组 removeEmpty(currentItem.children); // 子数组清理后为空,则删除当前元素 if (currentItem.children.length === 0) { array.splice(i, 1); } } else { // 没有children或不是数组的元素直接删除 array.splice(i, 1); } } } // 测试 let a = [ {children: [{children: [1,2]}, {children: [5,6]}]}, {children: [{children: []}, {children: [5,6]}]}, {children: [{children: []}, {children: []}]}, {children: []} ]; removeEmpty(a); console.log(a); // 输出符合预期结果
方案2:纯函数(返回新数组,不修改原数据)
如果需要保留原数组,推荐使用纯函数,返回处理后的新数组:
function removeEmptyPure(array) { return array.reduce((result, currentItem) => { // 过滤掉没有children或children不是数组的元素 if (!currentItem.children || !Array.isArray(currentItem.children)) { return result; } // 递归清理子数组 const cleanedChildren = removeEmptyPure(currentItem.children); // 只有子数组清理后不为空,才保留当前对象 if (cleanedChildren.length > 0) { result.push({ ...currentItem, children: cleanedChildren }); } return result; }, []); } // 测试 let a = [ {children: [{children: [1,2]}, {children: [5,6]}]}, {children: [{children: []}, {children: [5,6]}]}, {children: [{children: []}, {children: []}]}, {children: []} ]; const result = removeEmptyPure(a); console.log(result); // 输出预期结果
内容的提问来源于stack exchange,提问作者Hassan Raza
相关产品推荐
相关产品推荐

