2

I have an array of objects that have array within themselves. I want to loop through the object and delete any empty arrays that I have. The object is shown below:

let a=[{children:[{children:[1,2]},{children:[5,6]}]},
       {children:[{children:[]},{children:[5,6]}]},
       {children:[{children:[]},{children:[]}]},
       {children:[]}]

I am trying to achieve the desired result by applying the code below but I am getting an error saying 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)

Expected outcome:

  expected outcome =[{children:[{children:[1,2]},{children:[5,6]}]},
     {children:[{children:[5,6]}]}]

If there are adjustments I can make to the existing code or use a different approach please let me know. Thank you.

  • Do you mean also to remove empty objects, not just arrays? – IT goldman Jul 19 '22 at 18:30
  • You're facing this issue because you're decreasing the size of the array (splicing) while looping it from the end. As you remove an element, the size of the array decreases and the index used is out of bounds. – addybist Jul 19 '22 at 18:52
  • Kind of related to https://stackoverflow.com/questions/42736031/remove-empty-objects-from-an-object – Mr. Polywhirl Jul 19 '22 at 18:59
  • Yeh I mean to delete the empty objects too. And I am splicing from the end so that shouldn’t cause any issue? – Hassan Raza Jul 19 '22 at 19:18

3 Answers3

0

To achieve your goal you can use the .reduce() method.

const a = [{
    children: [{
      children: [1, 2]
    }, {
      children: [5, 6]
    }]
  },
  {
    children: [{
      children: []
    }, {
      children: [5, 6]
    }]
  },
  {
    children: [{
      children: []
    }, {
      children: []
    }]
  },
  {
    children: []
  }
]

const b = a.reduce((previousValue, currentValue) => {
  const data = []
  if (currentValue.children.length > 0) {
    currentValue.children.forEach((e) => {
      if (e.children.length > 0) data.push(e);
    });
  }
  if (data.length > 0) previousValue.push({children: data});
  return previousValue;
}, []);

console.log(b);
TymoteuszLao
  • 844
  • 1
  • 5
  • 16
0

Here is a prune function that reduces a node with children. Just make sure you wrap incoming data in a node with children.

For each of the nodes children, you filter the children based on the child count.

const data = [
  { children: [{ children: [1,2] }, { children: [5,6] }] },
  { children: [{ children: [] }, { children: [5,6] }] },
  { children: [{ children: [] }, { children: [] }] },
  { children: [] },
];

const prune = (node, key = 'children') =>
  node[key].reduce((prev, curr) =>
    (children => children.length
        ? { [key]: [...prev[key], { [key]: children }] }
        : prev)
      (curr[key].filter(child => child[key].length)),
    { [key]: [] });

const tree = prune({ children: data });

tree.children.forEach(child => console.log(JSON.stringify(child)));
.as-console-wrapper { top: 0; max-height: 100% !important; }
.as-console-row-code { font-size: smaller !important; }
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
0

var updatedArray = children.filter(item => item.children.length > 0)