From an array of objects, extract value of a property as array

From an array of objects, extract value of a property as array

I have JavaScript object array with the following structure:
objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

I want to extract a field from each object, and get an array containing the values, for example field foo would give array [ 1, 3, 5 ].
I can do this with this trivial approach:
function getFields(input, field) {
var output = [];
for (var i=0; i < input.length ; ++i) output.push(input[i][field]); return output; } var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ] Is there a more elegant or idiomatic way to do this, so that a custom utility function would be unnecessary? Note about suggested duplicate, it covers how to convert a single object to an array.

Solutions/Answers:

Solution 1:

Here is a shorter way of achieving it:

let result = objArray.map(a => a.foo);

or

let result = objArray.map(({ foo }) => foo)

You can also check Array.prototype.map().

Solution 2:

Yes, but it relies on an ES5 feature of JavaScript. This means it will not work in IE8 or older.

var result = objArray.map(function(a) {return a.foo;});

On ES6 compatible JS interpreters you can use an arrow function for brevity:

var result = objArray.map(a => a.foo);

Array.prototype.map documentation

Solution 3:

Check out Lodash’s _.pluck() function or Underscore’s _.pluck() function. Both do exactly what you want in a single function call!

var result = _.pluck(objArray, 'foo');

Update: _.pluck() has been removed as of Lodash v4.0.0, in favour of _.map() in combination with something similar to Niet’s answer. _.pluck() is still available in Underscore.

Update 2: As Mark points out in the comments, somewhere between Lodash v4 and 4.3, a new function has been added that provides this functionality again. _.property() is a shorthand function that returns a function for getting the value of a property in an object.

Additionally, _.map() now allows a string to be passed in as the second parameter, which is passed into _.property(). As a result, the following two lines are equivalent to the code sample above from pre-Lodash 4.

var result = _.map(objArray, 'foo');
var result = _.map(objArray, _.property('foo'));

_.property(), and hence _.map(), also allow you to provide a dot-separated string or array in order to access sub-properties:

var objArray = [
    {
        someProperty: { aNumber: 5 }
    },
    {
        someProperty: { aNumber: 2 }
    },
    {
        someProperty: { aNumber: 9 }
    }
];
var result = _.map(objArray, _.property('someProperty.aNumber'));
var result = _.map(objArray, _.property(['someProperty', 'aNumber']));

Both _.map() calls in the above example will return [5, 2, 9].

If you’re a little more into functional programming, take a look at Ramda’s R.pluck() function, which would look something like this:

var result = R.pluck('foo')(objArray);  // or just R.pluck('foo', objArray)

Solution 4:

Speaking for the JS only solutions, I’ve found that, inelegant as it may be, a simple indexed for loop is more performant than its alternatives.

Extracting single property from a 100000 element array (via jsPerf)

Traditional for loop 368 Ops/sec

var vals=[];
for(var i=0;i<testArray.length;i++){
   vals.push(testArray[i].val);
}

ES6 for..of loop 303 Ops/sec

var vals=[];
for(var item of testArray){
   vals.push(item.val); 
}

Array.prototype.map 19 Ops/sec

var vals = testArray.map(function(a) {return a.val;});

TL;DR – .map() is slow, but feel free to use it if you feel readability is worth more than performance.

Edit #2: 6/2019 – jsPerf link broken, removed.

Solution 5:

Using Array.prototype.map:

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
    });
}

See the above link for a shim for pre-ES5 browsers.

Solution 6:

It is better to use some sort of libraries like lodash or underscore for cross browser assurance.

In Lodash you can get values of a property in array by following method

_.map(objArray,"foo")

and in Underscore

_.pluck(objArray,"foo")

Both will return

[1, 2, 3]