Using javascript map() to convert values to objects - javascript

Sorry, it is probably quite trivial, still I can't find a solution for:
I have an object that contains the following elements:
0: "A"
1: "B"
2: "C"
I would like to use the map() function to convert it to something like this:
0: {name: "A"}
1: {name: "B"}
2: {name: "C"}
If I use this:
this.xxx = this.operations.map(obj => obj.name);
console.log(this.xxx);
or this:
this.xxx = this.operations.map(obj => {name:obj} );
console.log(this.xxx);
the elements of xxx are undefined.

When you write
someArray.map(obj => {
//this is a code block, not an object definition
} )
the curly braces enclose a code block, not an object literal.
If you want an arrow function to return an object, JS requires you to wrap the object literal with parentheses in order to correctly parse your intent.
As such:
this.operations.map(obj => ({name: obj}) )
will fix your mapping.
Alternatively, if you want to do something more complex, use a codeblock and return the value:
this.operations.map(obj => {
// do some calculations
return {name: obj};
})

If I understood you would like to turn them to object? That's how you could do:
var x = ["A", "B", "C"];
console.log(x.map(obj => {return {name: obj}}));

Map object values to array of objects and then convert it into object using Object.assign
var obj = {
0: "A",
1: "B",
2: "C",
};
console.log(Object.assign({},Object.values(obj).map(a => ({ name: a }))));

First of all, if you have object, not sure how you can work with map function overall, since it's array prototype function. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map however if its array you should try this:
const operations = [ "A", "B", "C"]
const xxx = operations.map(obj => ({name:obj}) );
console.log(xxx)
you were missing wrapping brackets, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Advanced_syntax
but if its really an object then this should work (not sure about performance):
const operations = {
0: "A",
1: "B",
2: "C",
}
const xxx = {}
Object.entries(operations).forEach(entry => {
xxx[entry[0]] = { name: entry[1] }
});
console.log(xxx)

Try this,with Object.entries
let obj = {
0: "A",
1: "B",
2: "C"
}
let result = Object.entries(obj).map(([,name]) => ({
name
}));
console.log(result)

Since the object is similar to an array you can add the length property making it array like in this way. Then you can convert it to a real array using Array.from passing the transformation function as the second argument:
const input = {
0: "A",
1: "B",
2: "C"
}
const result = Array.from(
{ ...input, length: Object.keys(input).length },
item => ({ name: item })
)
console.log(result)

You can't use .map() to produce an object, since it always returns an array.
Your best bet would be to get the entries in the object, then use .reduce() on it, like so:
const operations = {
0: 'A',
1: 'B',
2: 'C',
}
const res = Object.entries(operations)
.reduce((acc, [key, val], i) => { acc[i] = { [key]: val }; return acc },{})
console.log(res)

Related

convert 2 arrays into key value object, one array hold the keys, they second is nested array of matching indexed values

combine each irritation of valueArr it's inner member to a matching key from keysArr,
Index will always match each other.
the result I'm looking for: the key for each object and the id is equal to "internalid"
But i will work it out if it's not clear
const valuesArr =
["10","9","Item","Bank","2","true","true","Result7","5675"],
["9","1","Expenses","OthExpense","4","true","true","9999","9999"],
["8","8","Expenses","OthAsset","6","false","false","6666","77777"],
["7","8","Expenses","AcctPay","4","true","true","666","7777"],
["6","123","123","123","123","123","123","123","123"],
["5","123","123","123","123","123","123","123","123"],
["4","Test1","Item","OthCurrAsset","2","Result5","Result6","ytrytrytryrty","32432"],
["2","Result1","Result2","Result3","Result4","Result5","Result6","Result7","Result8"],
["1","Test1","Test12","Test13","Test14","Test15","Test16","Test17","Test18"]]
const keysArr =
["internalid",
"custrecord_st_segment_transaction_type",
"custrecord_st_segment_sublist",
"custrecord_st_segment_account_type",
"custrecord_st_segment_subsidiary",
"custrecord_st_segment_department",
"custrecord_st_segment_class",
"custrecord_st_segment_location",
"custrecord_st_segment_custom_segment"]
result:
{"1":{"id":"1","values":{"internalid":"1","custrecord_st_segment_transaction_type":"Test1","custrecord_st_segment_sublist":"Test12","custrecord_st_segment_account_type":"Test13","custrecord_st_segment_subsidiary":"Test14","custrecord_st_segment_department":"Test15","custrecord_st_segment_class":"Test16","custrecord_st_segment_location":"Test17","custrecord_st_segment_custom_segment":"Test18"}},
"2":{"id":"2","values":{"internalid":"2","custrecord_st_segment_transaction_type":"Result1","custrecord_st_segment_sublist":"Result2","custrecord_st_segment_account_type":"Result3","custrecord_st_segment_subsidiary":"Result4","custrecord_st_segment_department":"Result5","custrecord_st_segment_class":"Result6","custrecord_st_segment_location":"Result7","custrecord_st_segment_custom_segment":"Result8"}},
"4":{"id":"4","values":{"internalid":"4","custrecord_st_segment_transaction_type":"Test1","custrecord_st_segment_sublist":"Item","custrecord_st_segment_account_type":"OthCurrAsset","custrecord_st_segment_subsidiary":"2","custrecord_st_segment_department":"Result5","custrecord_st_segment_class":"Result6","custrecord_st_segment_location":"ytrytrytryrty","custrecord_st_segment_custom_segment":"32432"}},
"5":{"id":"5","values":{"internalid":"5","custrecord_st_segment_transaction_type":"123","custrecord_st_segment_sublist":"123","custrecord_st_segment_account_type":"123","custrecord_st_segment_subsidiary":"123","custrecord_st_segment_department":"123","custrecord_st_segment_class":"123","custrecord_st_segment_location":"123","custrecord_st_segment_custom_segment":"123"}},
"6":{"id":"6","values":{"internalid":"6","custrecord_st_segment_transaction_type":"123","custrecord_st_segment_sublist":"123","custrecord_st_segment_account_type":"123","custrecord_st_segment_subsidiary":"123","custrecord_st_segment_department":"123","custrecord_st_segment_class":"123","custrecord_st_segment_location":"123","custrecord_st_segment_custom_segment":"123"}},
"7":{"id":"7","values":{"internalid":"7","custrecord_st_segment_transaction_type":"8","custrecord_st_segment_sublist":"Expenses","custrecord_st_segment_account_type":"AcctPay","custrecord_st_segment_subsidiary":"4","custrecord_st_segment_department":"true","custrecord_st_segment_class":"true","custrecord_st_segment_location":"666","custrecord_st_segment_custom_segment":"7777"}},
"8":{"id":"8","values":{"internalid":"8","custrecord_st_segment_transaction_type":"8","custrecord_st_segment_sublist":"Expenses","custrecord_st_segment_account_type":"OthAsset","custrecord_st_segment_subsidiary":"6","custrecord_st_segment_department":"false","custrecord_st_segment_class":"false","custrecord_st_segment_location":"6666","custrecord_st_segment_custom_segment":"77777"}},
"9":{"id":"9","values":{"internalid":"9","custrecord_st_segment_transaction_type":"1","custrecord_st_segment_sublist":"Expenses","custrecord_st_segment_account_type":"OthExpense","custrecord_st_segment_subsidiary":"4","custrecord_st_segment_department":"true","custrecord_st_segment_class":"true","custrecord_st_segment_location":"9999","custrecord_st_segment_custom_segment":"9999"}},
"10":{"id":"10","values":{"internalid":"10","custrecord_st_segment_transaction_type":"9","custrecord_st_segment_sublist":"Item","custrecord_st_segment_account_type":"Bank","custrecord_st_segment_subsidiary":"2","custrecord_st_segment_department":"true","custrecord_st_segment_class":"true","custrecord_st_segment_location":"Result7","custrecord_st_segment_custom_segment":"5675"}}]
I think the OP is asking how to "zip" two arrays, where one has keys and one has values. If so, Object.fromEntries() is very useful.
A simple zip, goes like this:
// a simple zip
function zip(keys, values) {
return Object.fromEntries(
keys.map((key, index) => [key, values[index]])
);
}
The OP appears to want the lead element in the values array to be a specially named field in the new object as well as the key of the resulting object. Here, applying the simple zip...
function zip(keys, values) {
return Object.fromEntries(
keys.map((key, index) => [key, values[index]])
);
}
// the value array contains an "id" element at the start
// produce an object that looks like { id: number, values: {...} }
function objectFromValues(keys, values) {
return { id: values[0], values: zip(keys, values.slice(1)) }
}
const valuesArr = [
[1, "A", "B", "C"],
[2, "D", "E", "F"]
];
const keys = ["keyA", "keyB", "keyC"];
const result = valuesArr.reduce((acc, values) => {
acc[values[0]] = objectFromValues(keys, values);
return acc;
}, {});
console.log(result)

How to copy a variable arrray from another arrray in javascripts

I have an array as below:
const arr = [
{
title: 's4',
value: '124'
},
{
title: 's2',
value: '121'
},
{
title: 's3',
value: '122'
}
];
and I want to create a new another array copy from the old array same as below:
const arrCopy = [
{
value: '124'
},
{
value: '121'
},
{
value: '122'
}
];
then my code as below:
var arrCopy = [...arr,arr.value]
but it has a problem, so anyone help me, thanks.
Just as in the comment above you can use awesome Javascript functions, in this case, you would like to use the map function of your array to map every item of the array as you like.
const arrayMapped = yourArray.map(item => {
value: item.value
})
Here is another way using Javascript Destructuring, you just ask with properties would you like from the JS Object, in this case, you just like the value property.
const arrayMapped = yourArray.map(( { value } ) => ( { value } ))
How Array.map works
How Object Destructuring works
You can simply use Array.map, as it returns a new array with the required value.
const newArr = arr.map(element => ({ value: element.value }))
console.log(newArr);
For references : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
If you are allowed to import a library. Ramda has a lot of functions to work with arrays.
For your specific question, project would do the job.
import R from "ramda";
R.project(["value"], arr) //return equals arrCopy

How to return object value based on array value in JavaScript [duplicate]

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.
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().
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
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.
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)
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' ]
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]
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.
In ES6, you can do:
const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)
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.
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
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)
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}]);
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"]
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)
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
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');
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 :).
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));
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 ]
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!!!
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);
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)]);
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/
Destructure and get specific attributes from array of object:
const customerList = dealerUserData?.partyDetails.map(
({ partyId, custAccountId }) => ({
partyId,
custAccountId,
customerId: dealerUserData?._id,
userId: dealerUserData?.authUserID,
}),
);

ES6 way - Get unique values from a nested array by key

trying to improve my JS chops.
Is there a cleaner way to retrieve the property value from the array below, by key, from a nested object, removing duplicates and sorting them alphabetically?
Here's what I have:
getObjectValues(array, key){
var unique = [];
array.forEach(function(item){
item[key].forEach(function(value){
if (unique.indexOf(value) < 0) {
unique.push(value)
}
})
});
return unique.sort();
},
example array of object:
[
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
expected output should be an array:
var array = ['a','b','c']
You could just use a Set, and add all the items to it:
let arr = [
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
console.log(
Array.from(
new Set(
arr.reduce(
(carry, current) => [...carry, ...current.value],
[]
)
)
).sort()
)
If you need something concise, you may go as simple as that:
make use of Set to get rid of duplicates
employ Array.prototype.flatMap() (with slight touch of destructuring assignment) to extract value items from within all objects into single array
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...new Set(src.flatMap(({value}) => value))].sort()
console.log(result)
.as-console-wrapper{min-height:100%;}
If you need something really fast, you may do the following:
use Array.prototype.reduce() to turn your array into Set of unique records (looping through value items with Array.prototype.forEach and doing Set.prototype.add())
spread resulting Set into array and .sort() that
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...src.reduce((acc,{value}) =>
(value.forEach(acc.add, acc), acc), new Set())].sort()
console.log(result)
.as-console-wrapper{Min-height:100%;}

How to iterate over objects nested in array and return just value from property [duplicate]

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.
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().
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
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.
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)
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' ]
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]
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.
In ES6, you can do:
const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)
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.
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
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)
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}]);
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"]
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)
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
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');
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 :).
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));
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 ]
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!!!
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);
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)]);
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/
Destructure and get specific attributes from array of object:
const customerList = dealerUserData?.partyDetails.map(
({ partyId, custAccountId }) => ({
partyId,
custAccountId,
customerId: dealerUserData?._id,
userId: dealerUserData?.authUserID,
}),
);

Categories

Resources