0

How to deep remove all falsey values and empty objects using lodash ?

f.e. I want my object :

{ a:undefined, b:2, c:4, d:undefined , e:{ f:{} , g:null } }

to become:

{ b:2, c:4 };
7
  • What will happen for e:{ f:'somevalue , g:null } Commented Oct 20, 2020 at 13:10
  • e:{f:somevalue} Commented Oct 20, 2020 at 13:10
  • 1
    So it will recursively go through all objects? Also {} is not falsy. Commented Oct 20, 2020 at 13:13
  • Would a for .. of loop not work here? Then use an if and delete false properties? Commented Oct 20, 2020 at 13:15
  • 1
    please add your attempt. do you want to get a new object or only delete unwanted properties? do you have arrays as well? Commented Oct 20, 2020 at 13:51

3 Answers 3

2

var test = {
  a: undefined,
  b: 2,
  c: 4,
  d: undefined,
  e: {
    f: {},
    g: null
  }
};

function clean(obj) {
  for (var propName in obj) {
    if (_.isObject(obj[propName])) {
      clean(obj[propName]);
    }
    if (obj[propName] === null || obj[propName] === undefined || _.isObject(obj[propName]) && _.isEmpty(obj[propName])) {
      delete obj[propName];
    }
  }
}

clean(test);
console.log(test);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>

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

Comments

0

You could get the properties to delete and get a clean object. This approach mutates to original object.

function clean(value) {
    if (value === null || value === undefined) return true;
    if (typeof value !== 'object') return false;
    if (Array.isArray(value)) {
        let i = value.length;
        while (i--) if (clean(value[i])) value.splice(i, 1);
        return !value.length;
    }
    Object
        .keys(value)
        .filter(k => clean(value[k]))
        .forEach(Reflect.deleteProperty.bind(null, value));

    return !Object.keys(value).length;
}

const 
    object = { a: undefined, b: 2, c: 4, d: undefined, e: { f: {}, g: null } , h: [], i: [1, []], j: [[[], []]] };

clean(object);

console.log(object);

1 Comment

needless to ask why ... why?
0

The question is pretty vague and doesn't specify whether the original structure may or may not be mutated. There is also nothing in there about arrays.

This answer assumes that you don't want to mutate the original data structure and that "deep" also means to go through all array elements. If the object or array results in an empty instance the corresponding key will be removed.

function deepCompact(collection) {
  const add = _.isArray(collection)
            ? (collection, key, value) => collection.push(value)
            : (collection, key, value) => collection[key] = value;
  
  return _.transform(collection, (collection, value, key) => {
    if (_.isObject(value)) {
      value = deepCompact(value);
      if (_.isEmpty(value)) return;
    } else {
      if (!value) return;
    }
    add(collection, key, value);
  });
}

const data1 = {a: undefined, b: 2, c: 4, d: undefined, e: {f: {} , g: null}};
console.log(deepCompact(data1));
const data2 = [{a: 0, b: 2}, false, {c: [{d: null}]}, {e: [{f: 1}]}];
console.log(deepCompact(data2));
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

transform is comparable to reduce, however the first callback parameter is locked to the provided or default accumulator. This means you don't have to return the accumulator from the callback. The default accumulator of transform also differs from reduce. reduce uses the first element as the initial value, whereas transform uses a new object with the same prototype as the provided collection as the default value.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.