35

Is there some elegant way of filtering out falsey properties from this object with lodash/underscore? Similar to how _.compact(array) removes falsey elements from arrays

so from

{
  propA: true,
  propB: true,
  propC: false,
  propD: true,
}

returning

{
  propA: true,
  propB: true,
  propD: true,
}
user3598395
  • 385
  • 1
  • 4
  • 5

8 Answers8

34

Here are two vanilla javascript options:

A.: Iterate over the object's keys and delete those having a falsey value.

var obj = {
  propA: true,
  propB: true,
  propC: false,
  propD: true,
};

Object.keys(obj).forEach(key => {
  if (!obj[key]) delete obj[key];
});

console.log(obj);

See Object.keys() and Array.prototype.forEach()

B.: Iterate over the object's keys and add truthy values to a new object.

var obj = {
  propA: true,
  propB: true,
  propC: false,
  propD: true,
};

var filteredObj = Object.keys(obj).reduce((p, c) => {    
  if (obj[c]) p[c] = obj[c];
  return p;
}, {});

console.log(filteredObj);

See Object.keys() and Array.prototype.reduce()

canon
  • 40,609
  • 10
  • 73
  • 97
31

Lodash 4.0

Lodash 4.0 has _.pick, which takes an array of properties, and _.pickBy which takes a function as an argument and returns an object only containing the keys for which that function returns truthy which is what we want here, so it'd be:

filtered = _.pickBy(obj, function(value, key) {return value;})

Or, since _.pickBy defaults to using _.identity as it's second argument, (and that's essentially what we've written above,) it can just be written as:

filtered = _.pickBy(obj);

Underscore or Lodash prior to version 4.0

In underscore and old versions of lodash, there's just a single _.pick, which has both behaviors of _.pick and _.pickWith from v4. So you can do:

filtered = _.pick(obj, function(value, key) {return value;})

Or more succinctly:

filtered = _.pick(obj, _.identity)
Retsam
  • 30,909
  • 11
  • 68
  • 90
3

As partially mentioned in a comment, ES6 provided Object.entries() and in 2019 Object.fromEntries().

Allowing:

Object.fromEntries(Object.entries(obj).filter(([key, value]) => ...))

Ex:

const obj = {
  a: 12,
  b: 123,
};

const filteredObj = Object.fromEntries(
  Object.entries(obj).filter(
    ([_, value]) => value > 100
  )
);

console.log(filteredObj);
// {b: 123}
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
shfs
  • 31
  • 2
2

Unfortunately I cannot direclty comment on the posts above yet, so I create this extra post.

Since Lodash v4 the functionality described above has been moved to _.pickBy. With _.identity as default you could also change your code to:

var filtered = _.pickBy(obj);

See this JSBin for a working example.

Jonas
  • 21
  • 1
1

If you're using lodash, I'd recommend something like this:

var object = {
    propA: true,
    propB: true,
    propC: false,
    propD: true,
};

_.pick(object, _.identity);
// →
// {
//   propA: true,
//   propB: true,
//   propD: true
// }

The pick() function generates a new object that includes properties that the callback returns truthy for. So we can just use the identity() function as the callback, since it'll just return each property value.

Adam Boduch
  • 11,023
  • 3
  • 30
  • 38
0

From lodash 4, we can use pickBy() to get only the value equal to true.

const active = _.keys(_.pickBy(object));
Guillaume Raymond
  • 1,726
  • 1
  • 20
  • 33
Subrata Sarkar
  • 111
  • 2
  • 3
0
let temp = {
  propA: true,
  propB: true,
  propC: false,
  propD: true,
}

let obj = {}
for(x in temp){
   if(temp[x] == true){
     obj[x] = temp[x]
   }
}

console.log(obj)

Using for-in loop we can achieve it something like this.

FaizanSyed
  • 27
  • 1
  • 5
  • 1
    The question specifically asks how to perform this using either lodash or underscore. This is also a five year old question with an accepted answer which would mean that any new answers that are added should be pointing out what new aspect of the question they address. – Jason Aller Jul 28 '20 at 18:25
0

Another approach

const objFilter = (obj, condition) => {
    let newObj = {}
    for (const [key, value] of Object.entries(obj)) {
        if (condition(value)) {
            newObj = { ...newObj, [key]: value }
        }
    }
    return newObj
}

Fire like this:

const newData = objFilter(oldData, (value) => value.marked === false)
RomanistHere
  • 795
  • 7
  • 17