foucdeg
foucdeg

Reputation: 875

Underscore.js _.map function : skip a value

I am trying to use underscore.js _.map function on an array of objects, to get an array with a property of each object. That's the usual scenario, so :

var finalArray = _.map(myArray, function(obj) {
    return obj.myProperty;
});

But in some cases I need that nothing be added in the array. It could be something like :

var finalArray = _.map(myArray, function(obj) {
    if (!obj.ignore) {
        return obj.myProperty;
    }
});

The result of this is that an undefined value is pushed into the array, which is not the same as not pushing anything at all.

Is there a way for the map function not to push a value, or do I need to post-process my finalArray to remove the unwanted undefined's?

Upvotes: 32

Views: 43427

Answers (7)

Michael R
Michael R

Reputation: 1607

Try using lodash's compact(). It creates an array with all falsey values removed. Thus, the values false, null, 0, "", undefined, and NaN are removed.

https://lodash.com/docs#compact

I'm using it—it's very clean.

Upvotes: 3

Kevin Le - Khnle
Kevin Le - Khnle

Reputation: 10857

Here's another way. This one makes use of the compose function in underscore. Why compose? compose is backed by Category theory in Mathematics. This way is also point-free.

var pluckMyProp = function(array) {
    return _.pluck(array, 'myProperty')
}

var reject = function(array) {
    return _.reject(array, function(element) {
        return element['ignore'] === true
    })
}

var finalArray = _.compose(pluckMyProp, reject)
var data = [{myProperty: 1, ignore: false}, {ignore: true}, {myProperty: 2}]


finalArray(data) //=> [1,2]

Upvotes: 0

Pavlo
Pavlo

Reputation: 44917

This can be done using Underscore methods alone, points-free style:

var finalArray = _.chain(myArray)
    .reject('ignore')
    .pluck('myProperty')
    .value();

Upvotes: 14

Thomas Eschemann
Thomas Eschemann

Reputation: 995

You could use reduce:

myArray.reduce(function (acc, obj) {
    if (!obj.ignore) {
        acc.push(obj.myProperty);
    }
    return acc;
}, []);

or with lodash:

_.reduce(myArray, function (acc, obj) {
  if (!obj.ignore) {
    acc.push(obj.myProperty);
  }
  return acc;
}, []);

Upvotes: 31

Andreas Louv
Andreas Louv

Reputation: 47099

.map will map out a new value to the array, you can use .filter to filter the array. FYI you can use .pluck to map a property from an object:

_.chain(myArray).filter(function(obj) { return !obj.ignore; }).pluck('myProperty').value();

You can also use .where like this:

_.chain(myArray).where({ignore: false}).pluck('myProperty').value();

Or:

_.pluck(_.where(myArray, {ignore: false}), 'myProperty');

Upvotes: 5

couettos
couettos

Reputation: 591

you should use _.filter() before _.map()

var filteredArray = _.filter(myArray,function(obj) {
     return !obj.ignore;
});

var finalArray = _.map(filteredArray, function(obj) {
    return obj.myProperty;
});

Upvotes: 32

TaoPR
TaoPR

Reputation: 6052

So this means you want to filter, then map your array.

To do this in underscore way, you will need to pass your array into this pipeline:

myArray --> filter --> map --> finalArray

var isIncluded = function(obj){
    return !obj.ignore
}
var takeProperty = function(obj){
    return obj.myProperty
}
var finalArray = _.map( _.filter(myArray, isIncluded), takeProperty  );

Upvotes: 1

Related Questions