0

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)
 }

6
  • Does this answer your question? Remove empty objects from an object Commented Jul 9, 2020 at 9:12
  • I've tried the code it doesn't work. Commented Jul 9, 2020 at 9:14
  • Have you tried stackoverflow.com/q/52367849/7580839 ? Commented Jul 9, 2020 at 9:18
  • @Teemu that's not a recursive removal though—it won't remove nested objects that have empty values. Commented Jul 9, 2020 at 9:22
  • @rb612 My bad, didn't read the question carefully. Commented Jul 9, 2020 at 9:24

3 Answers 3

1

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));

Sign up to request clarification or add additional context in comments.

Comments

0

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));

Comments

-1

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))

1 Comment

The OP did mention -> The goal is to remove all empty fields. This just removes empty objects on the root, and empty objects called not..

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.