DoneDeal0
DoneDeal0

Reputation: 6257

How to remove empty nested objects in an array?

I have an array of objects, that can either have direct or nested values. The goal is to remove all empty fields.

For exemple:

 const todos = [ {}, { not: {} } ]
 // expected output: []
 
 const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
 // expected output: [{ not: {countries: ["uk", "us"]} }]

I've tried to filter the array with Object.values.length, it when a nested value is an empty object, it doesn't work anymore. Would someone know how to do it?

EDIT: So I've came up with my own solution which is a bit simpler from what I've read here:

 function foo(todos){
  todos.map((todo,i)=> {
     if(!Object.keys(todo).length){
       return todos.splice(i, 1)
     }
    if(Object.keys(todo).length){
      const key = Object.keys(todo) + ""
    return !Object.values(todo[key]).length && todos.splice(i, 1)
    }
      return todo
   })
   return todos.filter(c=> Object.keys(c).length)
 }

Upvotes: 0

Views: 1354

Answers (3)

Ghoul Ahmed
Ghoul Ahmed

Reputation: 4806

try with filter

const isEmpty = e => Object.entries(e).length
const removeEmptyObject = e => e.not?isEmpty(e.not):isEmpty(e)
 
 const todos = [ {}, { not: {} } ]
console.log(todos.filter(removeEmptyObject))
 
 const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
console.log(todos2.filter(removeEmptyObject))

Upvotes: -1

Keith
Keith

Reputation: 24181

Because your structure has a mix of Objects and Arrays, you will want to check for this.

Below is an example.

function trimEmptyObjects(o) {
  if (typeof o !== 'object') return o;
  if (Array.isArray(o)) {
    for (let i = o.length -1; i >= 0; i --) {
      o[i] = trimEmptyObjects(o[i]);
      if (typeof o[i] === 'object') {
        if (!Object.keys(o[i]).length) {
          o.splice(i, 1);
        }
      }
    }
    return o;
  } else {
    const e = Object.entries(o);
    for (let i = e.length -1; i >= 0; i --) {    
      e[i][1] = trimEmptyObjects(e[i][1]);
      if (typeof e[i][1] === 'object') {
        if (!Object.keys(e[i][1]).length) {
          e.splice(i, 1);
        }
      }
    }
    return Object.fromEntries(e);
  }
}


const todos = [ {}, { not: {} } ]
// expected output: []
console.log(trimEmptyObjects(todos));
 
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ]
// expected output: [{ not: {countries: ["uk", "us"]} }]
console.log(trimEmptyObjects(todos2));

Upvotes: 1

Rohit Tagadiya
Rohit Tagadiya

Reputation: 3730

I think you want like this..

const todos = [ {}, { not: {} } ];
const todos2 = [ {}, { not: {countries: ["uk", "us"]} } ];

function clean(object) {
    Object
        .entries(object)
        .forEach(([k, v]) => {
            if (v && typeof v === 'object') {
                clean(v);
            }
            if (v && typeof v === 'object' && !Object.keys(v).length || v === null || v === undefined) {
                if (Array.isArray(object)) {
                    object.splice(k, 1);
                } else {
                    delete object[k];
                }
            }
        });
    return object;
}

console.log(clean(todos));
console.log(clean(todos2));

Upvotes: 0

Related Questions