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

Asked 2023-09-21 08:09:50 View 154,752

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.

  • The Prototype library added a "pluck" function to the Array prototype (I think), so you could write var foos = objArray.pluck("foo");. - anyone
  • @hyde - jsperf.com/map-vs-native-for-loop - please have a look at this, hope plain looping itself an good solution - anyone
  • @N20084753 for a fair test you should also compare the native Array.prototype.map function where it exists - anyone
  • OP, I prefer your approach to any others that have been suggested. Nothing wrong with it. - anyone
  • @Pointy I think you are talking about function is _.pluck(objArray, "foo"), however this is part of the Underscore library. The best way is to use the .map available in ES6 - anyone

Answers

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().

Answered   2023-09-21 08:09:50

  • Well, this is same as another answer's comment by totymedli, but none-the-less it's actually better (in my opinion) way than in other answers, so... Changing it to accepted answer. - anyone
  • I really liked that one, btw, that => symbol smells like new thing to me, so i think that the compatibility of that solution needs to be reviewed if it is actually viable. - anyone
  • @PauloRoberto Arrow functions are basically supported everywhere except IE. - anyone
  • sure, it's permitted, but IMHO there's nothing that makes this answer objectively better, except that it uses a syntax that wasn't available at the time you asked the question and isn't even supported in some browsers. I'd also note that this answer is a direct copy of comments that were made on the originally accepted answer nearly a year before this answer was posted. - anyone
  • @Alnitak Using newer functionality, in my point of view, is objectively better. This snippet is extremely common, so I'm not convinced this is plagiarism. There isn't really any value in keeping outdated answers pinned to the top. - anyone

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

Answered   2023-09-21 08:09:50

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.

Answered   2023-09-21 08:09:50

  • I just re-tested it with jsBench (many thanks to Mirko Vukušić for creating an alternative to the jsPerf), results still the same - for is the fastest, for .. of is slightly slower, map is about a half slower. - anyone
  • They aren't the same as in the original answer, at least for me. In the original answer for .. of was ~16x the speed of map. Running the benchmark today, for .. of is ~2x the speed of map. - anyone
  • Very interesting point about performance consideration vs code readability, got me to read this which shed further light on the topic. leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of - anyone

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)

Answered   2023-09-21 08:09:50

Example to collect the different fields from the object array

let inputArray = [
  { id: 1, name: "name1", value: "value1" },
  { id: 2, name: "name2", value: "value2" },
];

let ids = inputArray.map( (item) => item.id);
let names = inputArray.map((item) => item.name);
let values = inputArray.map((item) => item.value);

console.log(ids);
console.log(names);
console.log(values);

Result :

[ 1, 2 ]
[ 'name1', 'name2' ]
[ 'value1', 'value2' ]

Answered   2023-09-21 08:09:50

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]

Answered   2023-09-21 08:09:50

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.

Answered   2023-09-21 08:09:50

In ES6, you can do:

const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)

Answered   2023-09-21 08:09:50

If you want multiple values in ES6+ the following will work

objArray = [ { foo: 1, bar: 2, baz: 9}, { foo: 3, bar: 4, baz: 10}, { foo: 5, bar: 6, baz: 20} ];

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

This works as {foo, baz} on the left is using object destructoring and on the right side of the arrow is equivalent to {foo: foo, baz: baz} due to ES6's enhanced object literals.

Answered   2023-09-21 08:09:50

The above answer is good for a single property but when select multiple properties from an array use this

var arrayObj=[{Name,'A',Age:20,Email:'a.gmail.com'},{Name,'B',Age:30,Email:'b.gmail.com'},{Name,'C',Age:40,Email:'c.gmail.com'}]

now I select only two fields

 var outPutArray=arrayObj.map(( {Name,Email} ) =>  ({Name,Email}) )
 console.log(outPutArray)

Answered   2023-09-21 08:09:50

While map is a proper solution to select 'columns' from a list of objects, it has a downside. If not explicitly checked whether or not the columns exists, it'll throw an error and (at best) provide you with undefined. I'd opt for a reduce solution, which can simply ignore the property or even set you up with a default value.

function getFields(list, field) {
    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  check if the item is actually an object and does contain the field
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

This would work even if one of the items in the provided list is not an object or does not contain the field.

It can even be made more flexible by negotiating a default value should an item not be an object or not contain the field.

function getFields(list, field, otherwise) {
    //  reduce the provided list to an array containing either the requested field or the alternative value
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

This would be the same with map, as the length of the returned array would be the same as the provided array. (In which case a map is slightly cheaper than a reduce):

function getFields(list, field, otherwise) {
    //  map the provided list to an array containing either the requested field or the alternative value
    return list.map(function(item) {
        //  If item is an object and contains the field, add its value and the value of otherwise if not
        return typeof item === 'object' && field in item ? item[field] : otherwise;
    }, []);
}

jsbin example

And then there is the most flexible solution, one which lets you switch between both behaviours simply by providing an alternative value.

function getFields(list, field, otherwise) {
    //  determine once whether or not to use the 'otherwise'
    var alt = typeof otherwise !== 'undefined';

    //  reduce the provided list to an array only containing the requested field
    return list.reduce(function(carry, item) {
        //  If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
        if (typeof item === 'object' && field in item) {
            carry.push(item[field]);
        }
        else if (alt) {
            carry.push(otherwise);
        }

        //  return the 'carry' (which is the list of matched field values)
        return carry;
    }, []);
}

jsbin example

As the examples above (hopefully) shed some light on the way this works, lets shorten the function a bit by utilising the Array.concat function.

function getFields(list, field, otherwise) {
    var alt = typeof otherwise !== 'undefined';

    return list.reduce(function(carry, item) {
        return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
    }, []);
}

jsbin example

Answered   2023-09-21 08:09:50

If you want to also support array-like objects, use Array.from (ES2015):

Array.from(arrayLike, x => x.foo);

The advantage it has over Array.prototype.map() method is the input can also be a Set:

let arrayLike = new Set([{foo: 1}, {foo: 2}, {foo: 3}]);

Answered   2023-09-21 08:09:50

If you have nested arrays you can make it work like this:

const objArray = [ 
     { id: 1, items: { foo:4, bar: 2}},
     { id: 2, items: { foo:3, bar: 2}},
     { id: 3, items: { foo:1, bar: 2}} 
    ];

    let result = objArray.map(({id, items: {foo}}) => ({id, foo}))
    
    console.log(result)

Answered   2023-09-21 08:09:50

I know there is a lot of answers provided already and cover huge range of solutions.

but i want to add somthing that i didn't find in all above answers.

and for example I will use the following type of data

const array = [
   {name:"foo",age:23, skills:["reactjs","nodejs","nextjs"]},
   {name:"bar",age:25, skills:["angular","java"]}
]

if you are extracting the a single attribute from all the indexes of the Object array then then it is ok to go only with map function as already answered by many community members and for reference I will code here:

array.map(a => a.skills);

the above code snippet will result in array of length 2 it means it will return the skills filed of both indexes,


So if you want to get the single field specific filed form an array object e.g. the skills of only bar, here is the example code for that by combining the filter and map functions

const array = [
       {name:"foo",age:23, skills:["reactjs","nodejs","nextjs"]},
       {name:"bar",age:25, skills:["angular","java"]}
    ]

    function getField(array, field) {
       return array.filter(a => a.name===field).map(a => a.skills);
    }
    console.log(getField(array,"bar"))


And finally if you want to a fully dynamic/generic code here it is

const array = [
  {name:"foo",age:23, skills:["reactjs","nodejs","nextjs"]},
  {name:"bar",age:25, skills:["angular","java"]}
]

function getFiled(array, fieldOf, fieldName) {
  return array.filter(a => a.name===fieldOf).map(a => a[fieldName]);
}
console.log(getFiled(array,"bar","skills"))

Answered   2023-09-21 08:09:50

In general, if you want to extrapolate object values which are inside an array (like described in the question) then you could use reduce, map and array destructuring.

ES6

let a = [{ z: 'word', c: 'again', d: 'some' }, { u: '1', r: '2', i: '3' }];
let b = a.reduce((acc, obj) => [...acc, Object.values(obj).map(y => y)], []);

console.log(b)

The equivalent using for in loop would be:

for (let i in a) {
  let temp = [];
  for (let j in a[i]) {
    temp.push(a[i][j]);
  }
  array.push(temp);
}

Produced output: ["word", "again", "some", "1", "2", "3"]

Answered   2023-09-21 08:09:50

Easily extracting multiple properties from array of objects:

let arrayOfObjects = [
  {id:1, name:'one', desc:'something'},
  {id:2, name:'two', desc:'something else'}
];

//below will extract just the id and name
let result = arrayOfObjects.map(({id, name}) => ({id, name}));

result will be [{id:1, name:'one'},{id:2, name:'two'}]

Add or remove properties as needed in the map function

Answered   2023-09-21 08:09:50

In ES6, in case you want to dynamically pass the field as a string:

function getFields(array, field) {
    return array.map(a => a[field]);
}

let result = getFields(array, 'foo');

Answered   2023-09-21 08:09:50

It depends on your definition of "better".

The other answers point out the use of map, which is natural (especially for guys used to functional style) and concise. I strongly recommend using it (if you don't bother with the few IE8- IT guys). So if "better" means "more concise", "maintainable", "understandable" then yes, it's way better.

On the other hand, this beauty doesn't come without additional costs. I'm not a big fan of microbench, but I've put up a small test here. The results are predictable, the old ugly way seems to be faster than the map function. So if "better" means "faster", then no, stay with the old school fashion.

Again this is just a microbench and in no way advocating against the use of map, it's just my two cents :).

Answered   2023-09-21 08:09:50

create an empty array then forEach element from your list, push what you want from that object into your empty array.

 let objArray2 = [];
 objArray.forEach(arr => objArray2.push(arr.foo));

Answered   2023-09-21 08:09:50

  • Comment was edited, thanks for your explanation. - anyone

From an array of objects, extract the value of a property as an array with for loop.

//input
objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ]; 

//Code
let output=[];
for(let item of objArray){
    output.push(item.foo); 
}

// Output
[ 1, 3, 5 ]

Answered   2023-09-21 08:09:50

Above provided answer is good for extracting single property, what if you want to extract more than one property from array of objects. Here is the solution!! In case of that we can simply use _.pick(object, [paths])

_.pick(object, [paths])

Lets assume objArray has objects with three properties like below

objArray = [ { foo: 1, bar: 2, car:10}, { foo: 3, bar: 4, car:10}, { foo: 5, bar: 6, car:10} ];

Now we want to extract foo and bar property from every object and store them in a separate array. First we will iterate array elements using map and then we apply Lodash Library Standard _.pick() method on it.

Now we are able to extract 'foo' and 'bar' property.

var newArray = objArray.map((element)=>{ return _.pick(element, ['foo','bar'])}) console.log(newArray);

and result would be [{foo: 1, bar: 2},{foo: 3, bar: 4},{foo: 5, bar: 6}]

enjoy!!!

Answered   2023-09-21 08:09:50

  • Where does _.pick come from ? It isn't a standard function. - anyone
  • I just updated answer, _.pick() is a standard method of Lodash library. - anyone

Here is another shape of using map method on array of objects to get back specific property:

const objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

const getProp = prop => obj => obj[prop];
const getFoo = getProp('foo');
const fooes = objArray.map(getFoo);
console.log(fooes);

Answered   2023-09-21 08:09:50

I would only improve one of the answers if you even don't know the exact property of the object you'r playing with use below:

let result = objArray.map(a => a[Object.getOwnPropertyNames(a)]);

Answered   2023-09-21 08:09:50

Function map is a good choice when dealing with object arrays. Although there have been a number of good answers posted already, the example of using map with combination with filter might be helpful.

In case you want to exclude the properties which values are undefined or exclude just a specific property, you could do the following:

    var obj = {value1: "val1", value2: "val2", Ndb_No: "testing", myVal: undefined};
    var keysFiltered = Object.keys(obj).filter(function(item){return !(item == "Ndb_No" || obj[item] == undefined)});
    var valuesFiltered = keysFiltered.map(function(item) {return obj[item]});

https://jsfiddle.net/ohea7mgk/

Answered   2023-09-21 08:09:50

Destructure and get specific attributes from array of object:

const customerList = dealerUserData?.partyDetails.map(
  ({ partyId, custAccountId }) => ({
    partyId,
    custAccountId,
    customerId: dealerUserData?._id,
    userId: dealerUserData?.authUserID,
  }),
);

Answered   2023-09-21 08:09:50