Skip to content
Advertisement

Remove empty objects from an object

I am trying to remove empty objects inside an object, here is an example with the expected output:

var object = {
    a: {
        b: 1,
        c: {
            a: 1,
            d: {},
            e: {
              f: {} 
            }
        }
    },
    b: {}
}


var expectedResult = {
    a: {
        b: 1,
        c: {
            a: 1,
        }
    }
}

I tried using some examples from other StackOverflow questions, however those are just for one level objects.

Advertisement

Answer

Basic function that removes empty objects

First start with a function that only works with a single level of nesting.

This function removes all properties that reference an empty object:

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue // If null or not an object, skip to the next iteration
    }

    // The property is an object
    if (Object.keys(o[k]).length === 0) {
      delete o[k]; // The object had no properties, so delete that property
    }
    return o;
  }
}

Handling nested objects using recursion

Now you want to make it recursive so that it will operate on nested objects. So we already have tested if o[k] is an object, and we’ve tested if there are properties, so if there are, we simply call the function again with that nested object.

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue // If null or not an object, skip to the next iteration
    }

    // The property is an object
    clearEmpties(o[k]); // <-- Make a recursive call on the nested object
    if (Object.keys(o[k]).length === 0) {
      delete o[k]; // The object had no properties, so delete that property
    }
  }
    return o;
}

So just as the original call to clearEmpties removes properties of the given object that reference an empty object, likewise the recursive call will do the same for the nested objects.


Live demo:

var object = {
  a: {
    b: 1,
    c: {
      a: 1,
      d: {},
      e: { // will need to be removed after f has been removed
         f: {} 
      }
    }
  },

  b: {}
};

clearEmpties(object);
console.log(object);

function clearEmpties(o) {
  for (var k in o) {
    if (!o[k] || typeof o[k] !== "object") {
      continue
    }

    clearEmpties(o[k]);
    if (Object.keys(o[k]).length === 0) {
      delete o[k];
    }
  }
  return o;
}

Short version using Underscore and functional style

function clearEmpties(o) {
  if (_.isFunction(o) || !_.isObject(o)) return o;
  return _.chain(o)
    .mapObject(clearEmpties)
    .pick(p => !(_.isObject(p) && _.isEmpty(p)))
    .value();
}

Short version using lodash and functional style – works with treeshaking

import { isFunction, isObject, isEmpty, isArray, isPlainObject, fromPairs } from "lodash-es";

const removeEmtpyObjects = (o) => {
    if (isFunction(o) || !isPlainObject(o)) return o;

    if (isArray(o)) return o.map(removeEmtpyObjects);

    return fromPairs(
        Object.entries(o)
            .map(([k, v]) => [k, removeEmtpyObjects(v)])
            .filter(([k, v]) => !(v == null || (isObject(v) && isEmpty(v))))
    );
};
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement