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