This question already has answers here:
How to convert an array of objects to object with key value pairs
(7 answers)
How to convert an array of key-value tuples into an object
(14 answers)
Closed 5 years ago.
I would like to turn this:
let myArray = [ {city: "NY"}, {status: 'full'} ];
to this:
let myObj = { city: "NY", status: 'full' };
while I tried this:
let newObj = {};
for (var i = 0; i < myArray.length; i++) {
(function(x) {
newObj = Object.assign(myArray[i]);
})(i);
}
it assigns the last pair to the object
Spread the array into Object#assign:
const myArray = [ {city: "NY"}, {status: 'full'} ];
const myObj = Object.assign({}, ...myArray);
console.log(myObj);
Note: Assign into an empty object. If you omit the empty object, the 1st element of the original array will be mutated (everything will be merged into it).
You could also use Array.reduce() which will give you more fine grain control:
const myArray = [
{ city: 'NY', color: 'blue', rodents: { small: false, medium: false, large: true } },
{ status: 'full', color: 'red' },
{ sandwich: 'flavourful' },
]
// item is each object in your array
const reduced = myArray.reduce((newObj, item) => {
// existing props will be overwritten by newer object entries in the array
// this example is same as Object.assign spread with right to left precedence,
// until you want more custom logic
Object.keys(item).forEach((key) => { newObj[key] = item[key] })
return newObj
}, {})
console.log(reduced)
// you will see `red` overwrite `blue`
EDIT: after examining this answer after a year, I note that it isn't optimized at all for ability to deep clone or deep merge. I recommend studying those aspects closer and to be careful of copying or breaking references if you are working immutably.
There is no issue with this in the above example because all values are primitives.
I would tend to agree with Ori that your question seems to be about creating an indexed object which isn't usually a good plan, but if its necessary to key your object with numbers you can do it like this:
let newObj = {};
myArray.forEach((val, index) => { newObj[index] = val });
let myArray = [ {city: "NY"}, {status: 'full'} ];
let newObj = myArray.reduce((acc, curr) => {
Object.keys(curr).forEach(val => {
acc[val] = curr[val]
})
return acc
}, {})
console.log(newObj)
This syntax is supported in IE according to caniuse.com
Related
I have two arrays of objects (10 objects in each arrray) ->
arr1 = [{name: '', age: ''}...]
and
arr2 = [{surname: '', position: ''}...]
which I hold in two separated states.
My goal is to create the third array of the objects which contains also 10 elements
arr3=[{name: arr1.name, surname: arr2.surname}...]
How can I do this ?
As long as it is a 1 to 1 where each index matches, it is a simple Array map and using the spread to copy over the properties and values.
const arr1 = [{a: 1, b: 2}, {a: 3, b: 4}];
const arr2 = [{c: 11, d: 22}, {c: 33, d: 44}];
const arr3 = arr1.map((obj, ind) => ({...obj, ...arr2[ind]}), []);
console.log(arr3);
This is what you need,
let arr3 = []
arr1.forEach((obj1, index) => {
let obj3 = {...obj1, ...arr2[index]}
arr3.push(obj3)
})
If the indexes are assumed to match between the two arrays (which also implies that the two arrays are the same length), you can use map() on one array and use its index parameter to reference the other array. (It doesn't really matter which.)
For example:
const arr3 = arr1.map((a, i) => ({
name: a.name,
surname: arr2[i].surname
}));
Note that this is based on the example shown, where only two properties (one from each array) are in the resulting objects. If you want all properties in the resulting objects, you don't need to specify all of them. You can just combine them all:
const arr3 = arr1.map((a, i) => ({
...a,
...arr2[i]
}));
Here is how you could combine both arrays using a for loop:
const arr3 = []
for (let i = 0; i < arr1.length; i++) {
arr3[i] = {
name: arr1[i].name,
surname: arr2[i].surname
}
}
I don't get exactly what do you want to do but I think this question has been answered a few times.
You wanna do arr1 + arr2 ? Like they follow each others in the array3 ?
I have a question regarding the spread syntax and an array of objects.
Having an array of objects like:
const array = [{age:50}, {age:27}]
According to this answer: https://stackoverflow.com/a/54138394/6781511, using the spread syntax will result in referencedArray having a shallow copy of array.
const referencedArray = [...array]
What then is the difference between using the spread syntax and not using it?
const referencedArray = [...array]
vs
const referencedArray = array
See the following example.
When you make a shallow copy, assigning to an element of the original doesn't affect the clone. When you don't make a copy, assigning to the original affects the other reference.
Since it's a shallow copy, assigning to properties of the objects in the array affects all of them. Only the array was copied by spreading, not the objects.
const array = [{age:50}, {age:27}];
const clonedArray = [...array];
const notClonedArray = array;
array[0] = {age: 100};
array[1].age = 30;
console.log("Original:", array);
console.log("Cloned:", clonedArray);
console.log("Not cloned:", notClonedArray);
The objects within the arrays have the same reference in both, but in the spread scenario, modifying the array will not affect the original.
const array = [{ name: 'Joe' }, { name: 'Paul' }];
const spreadArray = [...array];
const cloneArray = array;
spreadArray[3] = { name: 'Bob' };
console.log(array); // [{ name: 'Joe' }, { name: 'Paul' }];
cloneArray[3] = { name: 'Bob' };
console.log(array); // [{ name: 'Joe' }, { name: 'Paul' }, { name: 'Bob'} ];
That's because cloneArray is assigned by reference to array, while spreadArray is assigned to a new array with the same elements as array. That's also why
cloneArray === array; // true
spreadArray === array; // false
I have an array containing objects that every element but the last one are objects, but I want to convert them into an array of arrays and add the last element.
To be more explicit here is how I have it:
[
{ 0: [1,2], 1: [6,2], name: "" },
{ 0: [3,4], 1: [2,2], name: "" }
]
and the result I want is this one:
[
{ multipolygon: [ [1,2], [6,2] ], name: ""},
{ multipolygon: [ [3,4], [2,2] ], name: ""}
]
Each single array contained inside the original array is converted into an array of those arrays.
I have tried doing this:
const zonesArray = zones.map(el => Object.values(el)) // obj => array
const polygons = zonesArray.filter(el => el.pop()) // array without name
to get all the arrays contained inside the obj but then I realized how can I replace this into the original objects.
I have tried to modify the groupBy function found on MDN:
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property]
if (!acc[key]) {
acc[key] = []
}
acc[key].push(obj)
return acc
}, {})
}
But I can't seem to find the answer
It doesn't look like you're trying to group by a property, you're trying to transform each object in the array separately - which can be done by taking the name and the numeric properties together when mapping, then returning the shape of the new object:
const arr = [
{ 0: [1,2], 1: [6,2], name: "" },
{ 0: [3,4], 1: [2,2], name: "" }
];
const result = arr.map(({ name, ...rest }) => ({
name,
multipolygon: Object.values(rest)
}));
console.log(result);
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Javascript: How to Get Object property using Array of string? [duplicate]
(7 answers)
Set nested item in object/array from array of keys
(4 answers)
Closed 3 years ago.
I have a JavaScript object, that is multiple levels deep, for example:
let obj = [
{
"testKeyOne": "one",
"testKeyTwo": "two"
},
{
"testKeyThree": "three",
"testKeyFour": "four",
"testKeyFive": {
"testKeyFiveAndAHalf": "5.5"
"testKeyFiveAndThreeQuarters": "5.75"
}
},
]
I also have an array for the key of what I need to access, for example, if I'm looking for the 5.5 one,
let array = [1, "testKeyFive", "testKeyFiveAndAHalf"]
though my array may also look like this if I'm looking for "one"
let array = [0, "testKeyOne"]
Is there any way to use the array to access the desired value?
This is my first time asking a question so if I messed up or if there is anything unclear or something that needs to be changed I apologize.
Thank you!
Yep. You can just use a reduce on the array:
let result = array.reduce((value, entry) => value[entry], obj);
let desired = obj;
while(array.length > 0) { desired = desired[array[0]]; array.shift() }
console.log(desired)
this should work
Here's one way to do it:
let obj = [{
"testKeyOne": "one",
"testKeyTwo": "two"
},
{
"testKeyThree": "three",
"testKeyFour": "four",
"testKeyFive": {
"testKeyFiveAndAHalf": "5.5",
"testKeyFiveAndThreeQuarters": "5.75"
}
},
]
let arr = [
[1, "testKeyFive", "testKeyFiveAndAHalf"],
[0, "testKeyOne"]
]
function foo(objArr, accessArr) {
for (const [index, ...keys] of accessArr) {
let obj = objArr[index];
for (const key of keys) {
obj = obj[key];
}
console.log(obj)
}
}
foo(obj, arr);
You can use a recursive function like that
let obj = [{
testKeyOne: "one",
testKeyTwo: "two"
},
{
testKeyThree: "three",
testKeyFour: "four",
testKeyFive: {
testKeyFiveAndAHalf: "5.5",
testKeyFiveAndThreeQuarters: "5.75"
}
}
];
let array = [1, "testKeyFive", "testKeyFiveAndAHalf"];
function getValue(arr, obj) {
const [first, ...rest] = arr;
return typeof(obj[first]) === "object" ? getValue(rest, obj[first]) : obj[first];
}
console.log(getValue(array, obj));
I've got two arrays that have multiple objects
[
{
"name":"paul",
"employee_id":"8"
}
]
[
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
}
]
How can I achieve the following with either ES6 or Lodash?
[
{
"name":"paul",
"employee_id":"8"
"data": {
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
}
]
I can merge but I'm not sure how to create a new child object and merge that in.
Code I've tried:
school_data = _.map(array1, function(obj) {
return _.merge(obj, _.find(array2, {employee_id: obj.e_id}))
})
This merges to a top level array like so (which is not what I want):
{
"name":"paul",
"employee_id":"8"
"years_at_school": 6
"department":"Mathematics",
"e_id":"8"
}
The connector between these two is "employee_id" and "e_id".
It's imperative that it's taken into account that they could be 1000 objects in each array, and that the only way to match these objects up is by "employee_id" and "e_id".
In order to match up employee_id and e_id you should iterate through the first array and create an object keyed to employee_id. Then you can iterate though the second array and add the data to the particular id in question. Here's an example with an extra item added to each array:
let arr1 = [
{
"name":"mark",
"employee_id":"6"
},
{
"name":"paul",
"employee_id":"8"
}
]
let arr2 = [
{
"years_at_school": 6,
"department":"Mathematics",
"e_id":"8"
},
{
"years_at_school": 12,
"department":"Arr",
"e_id":"6"
}
]
// empObj will be keyed to item.employee_id
let empObj = arr1.reduce((obj, item) => {
obj[item.employee_id] = item
return obj
}, {})
// now lookup up id and add data for each object in arr2
arr2.forEach(item=>
empObj[item.e_id].data = item
)
// The values of the object will be an array of your data
let merged = Object.values(empObj)
console.log(merged)
If you perform two nested O(n) loops (map+find), you'll end up with O(n^2) performance. A typical alternative is to create intermediate indexed structures so the whole thing is O(n). A functional approach with lodash:
const _ = require('lodash');
const dataByEmployeeId = _(array2).keyBy('e_id');
const result = array1.map(o => ({...o, data: dataByEmployeeId.get(o.employee_id)}));
Hope this help you:
var mainData = [{
name: "paul",
employee_id: "8"
}];
var secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
var finalData = mainData.map(function(person, index) {
person.data = secondaryData[index];
return person;
});
Sorry, I've also fixed a missing coma in the second object and changed some other stuff.
With latest Ecmascript versions:
const mainData = [{
name: "paul",
employee_id: "8"
}];
const secondaryData = [{
years_at_school: 6,
department: "Mathematics",
e_id: "8"
}];
// Be careful with spread operator over objects.. it lacks of browser support yet! ..but works fine on latest Chrome version for example (69.0)
const finalData = mainData.map((person, index) => ({ ...person, data: secondaryData[index] }));
Your question suggests that both arrays will always have the same size. It also suggests that you want to put the contents of array2 within the field data of the elements with the same index in array1. If those assumptions are correct, then:
// Array that will receive the extra data
const teachers = [
{ name: "Paul", employee_id: 8 },
{ name: "Mariah", employee_id: 10 }
];
// Array with the additional data
const extraData = [
{ years_at_school: 6, department: "Mathematics", e_id: 8 },
{ years_at_school: 8, department: "Biology", e_id: 10 },
];
// Array.map will iterate through all indices, and gives both the
const merged = teachers.map((teacher, index) => Object.assign({ data: extraData[index] }, teacher));
However, if you want the data to be added to the employee with an "id" matching in both arrays, you need to do the following:
// Create a function to obtain the employee from an ID
const findEmployee = id => extraData.filter(entry => entry.e_id == id);
merged = teachers.map(teacher => {
const employeeData = findEmployee(teacher.employee_id);
if (employeeData.length === 0) {
// Employee not found
throw new Error("Data inconsistency");
}
if (employeeData.length > 1) {
// More than one employee found
throw new Error("Data inconsistency");
}
return Object.assign({ data: employeeData[0] }, teacher);
});
A slightly different approach just using vanilla js map with a loop to match the employee ids and add the data from the second array to the matching object from the first array. My guess is that the answer from #MarkMeyer is probably faster.
const arr1 = [{ "name": "paul", "employee_id": "8" }];
const arr2 = [{ "years_at_school": 6, "department": "Mathematics", "e_id": "8" }];
const results = arr1.map((obj1) => {
for (const obj2 of arr2) {
if (obj2.e_id === obj1.employee_id) {
obj1.data = obj2;
break;
}
}
return obj1;
});
console.log(results);