How do I use Object.assign to update the second object in the allMsgs array?
I have:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
}
I want to have a copy of v so that it is:
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: ['newItem],
}
]
}
How do I use Object.assign for this?
Simply select the part which you want to update
let v = {
allMsgs: [
{
a: 111,
b: [],
},
{
a: 222,
b: [],
}
]
};
let vCopy = { allMsgs: v.allMsgs.map(msg => Object.assign({}, msg))};
vCopy.allMsgs[1] = Object.assign(vCopy.allMsgs[1], { b: ['newItem'] });
console.log('copy', vCopy);
console.log('actual', v);
Without Object.assign, you could address the array directly and push the value.
var v = { allMsgs: [{ a: 111, b: [] }, { a: 222, b: [] }] };
v.allMsgs[1].b.push('newItem');
console.log(v);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If the goal is not to mutate the original object, then you would do it like this:
let v = {
allMsgs: [
{ a: 111, b: [] },
{ a: 222, b: [] }
]
};
let w = { allMsgs: Object.assign([...v.allMsgs],
{ 1: Object.assign({}, v.allMsgs[1],
{b: ['newItem']}
)}
)};
console.log('updated =', w);
console.log('original =', v);
Note that here the first object in allMsgs is still shared between the two objects. Only the one you wanted to change is (obviously) separate.
Libraries like immutable.js have nice methods for making such updates using a concise syntax.
Related
How can we compare two array of objects on the basis of their keys or properties of object in javaScript?
for an example:
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
result1.filter(function (obj) {
return !result2.some(function (obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1?.forEach((x, index1) => {
key2?.forEach((y, index2) => {
console.log(index1, index2)
if (x === y) {
return obj[x] === obj2[y];
}
});
});
});
});
console.log(result1)
output: current output
expected output:
result1 =
[
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
I just try this solution in a different way, We can also achieve this requirement by doing deep copy of original array and then mutate it using forEach().
Live Demo :
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 }
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 }
];
const clone = structuredClone(result1);
clone.forEach((obj, index) => {
result1[index] = {};
Object.keys(result2[index]).forEach(key => {
result1[index][key] = obj[key]
});
});
console.log(result1);
let result1 = [
{ a: 10, b: 20, c: 22 },
{ a: 20, b: 33, c: 11 },
];
let result2 = [
{ a: 10, b: 20 },
{ a: 20, b: 33 },
];
let temp = []
result1.map(function(obj) {
return !result2.some(function(obj2) {
let key1 = Object.keys(obj);
let key2 = Object.keys(obj2);
key1.forEach((x) => {
key2.forEach((y) => {
if (x === y) {
obj[x] === obj2[y] ? temp.push({
[x]: obj[x]
}) : null;
}
})
});
})
})
console.log(temp);
try this code
You are getting the result1 array back beacause the array is not getting filtered.
The filter function is not getting anything from returned as the first foreach loop is not returning and the some function is also not returning anything
Now you can use map function instead of filter as the function is not returning anything
const filterKeysBasedOnFirstArrayOfObjects = <
T extends Record<string, unknown>
>(
arr1: T[],
arr2: T[]
) => {
const keys = _.intersection(
...arr1.map((obj) => Object.keys(obj)),
...arr2.map((obj) => Object.keys(obj))
);
return arr1.map((obj) => _.pick(obj, keys));
};
A more concise approach using lodash.
Given input:
[{ a: 1 }, { b: 2 }, { c: 3 }]
How to return:
{ a: 1, b: 2, c: 3 }
For arrays it's not a problem with lodash but here we have array of objects.
Use Object.assign:
let merged = Object.assign(...arr); // ES6 (2015) syntax
var merged = Object.assign.apply(Object, arr); // ES5 syntax
Note that Object.assign is not yet implemented in many environment and you might need to polyfill it (either with core-js, another polyfill or using the polyfill on MDN).
You mentioned lodash, so it's worth pointing out it comes with a _.assign function for this purpose that does the same thing:
var merged = _.assign.apply(_, [{ a: 1 }, { b: 2 }, { c: 3 }]);
But I really recommend the new standard library way.
With lodash, you can use merge():
var arr = [ { a: 1 }, { b: 2 }, { c: 3 } ];
_.merge.apply(null, [{}].concat(arr));
// → { a: 1, b: 2, c: 3 }
If you're doing this in several places, you can make merge() a little more elegant by using partial() and spread():
var merge = _.spread(_.partial(_.merge, {}));
merge(arr);
// → { a: 1, b: 2, c: 3 }
Here is a version not using ES6 methods...
var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var obj = {};
for(var i = 0; i < arr.length; i++) {
var o = arr[i];
for(var key in o) {
if(typeof o[key] != 'function'){
obj[key] = o[key];
}
}
}
console.log(obj);
fiddle: http://jsfiddle.net/yaw3wbb8/
You can use underscore.extend function like that:
var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = _.extend.apply(null, a);
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1, b: 2, c: 3 }, { b: 2 }, { c: 3 } ]
And to prevent modifying original array you should use
var _ = require('underscore');
var a = [{ a: 1 }, { b: 2 }, { c: 3 }];
var result = _.extend.apply(null, [{}].concat(a));
console.log(result); // { a: 1, b: 2, c: 3 }
console.log(a); // [ { a: 1 }, { b: 2 }, { c: 3 } ]
Here can test it
Adding to the accepted answer, a running code snippet with ES6.
let input = [{ a: 1 }, { b: 2 }, { c: 3 }]
//Get input object list with spread operator
console.log(...input)
//Get all elements in one object
console.log(Object.assign(...input))
I've got a neat little solution not requiring a polyfill.
var arr = [{ a: 1 }, { b: 2 }, { c: 3 }];
var object = {};
arr.map(function(obj){
var prop = Object.getOwnPropertyNames(obj);
object[prop] = obj[prop];
});
Hope that helps :)
Here is a nice usage of Object.assign with the array.prototype.reduce function:
let merged = arrOfObjs.reduce((accum, val) => {
Object.assign(accum, val);
return accum;
}, {})
This approach does not mutate the input array of objects, which could help you avoid difficult to troubleshoot problems.
With more modern spread operator
arrOfObj.reduce( (acc, curr) => ({ ...acc, ...cur }) );
You can easily flat your object to array.
function flatten(elements) {
return elements.reduce((result, current) => {
return result.concat(Array.isArray(current) ? flatten(current) : current);
}, []);
};
6 years after this question was asked.
Object.assign is the answer (above) I like the most.
but is this also legal ?
let res = {};
[{ a: 1 }, { b: 2 }, { c: 3 }].forEach(val => {
let key = Object.keys(val);
console.log(key[0]);
res[key] = val[key];
})
const data = [
[{ a: "a" }, { b: "b" }, { c: "c" }],
[{ d: "d" }, { e: "e" }, { f: "f" }],
[{ g: "g" }, { h: "h" }, { i: "i" }],
];
function convertToObject(array){
const response = {};
for (let i = 0; i < array.length; i++) {
const innerArray = array[i];
for (let i = 0; i < innerArray.length; i++) {
const object = innerArray[i];
const keys = Object.keys(object);
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
response[key] = object[key];
}
}
}
return response;
}
console.log(convertToObject(data));
function carParts(manufacturer, model, ...parts) {
return { manufacturer, model, ...Object.assign(...parts) };
}
console.log(
carParts(
"Honda",
"2008",
{ color: "Halogen Lights" },
{ Gears: "Automatic Gears" },
{ LED: "Android LED" },
{ LED: "Android LED1" }
)
);
This is how i have done.
I have two objects:
let first = {
a: 'John',
b: 22,
c: 'example'
}
let second = {
b: 55,
d: 'demo'
}
I want to replace only already existing items from second object to first one. Result should look like this (so only b item should be changed, and new d item ignored):
{
a: 'John',
b: 55, // changed
c: 'example'
}
Merge will not work because it will add also new item.
I can use foreach but I believe that there should be shorted answer for this. I'm already using lodash in my project so I can use function from there, but I cannot find any for this purpose. Is there any?
With lodash you could do something like this with _.merge, _.pick and _.keys:
let first = {
a: 'John',
b: 22,
c: 'example'
}, second = {
b: 55,
d: 'demo'
}
let result = _.merge(first, _.pick(second, _.keys(first)))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
With ES6 you can use Object.keys and then Array.forEach on a new object like this:
let first = {
a: 'John',
b: 22,
c: 'example'
}, second = {
b: 55,
d: 'demo'
}, result = new Object(null)
Object.keys(first).forEach(k => result[k] = second[k] || first[k])
console.log(result)
This assumes you do not want to mutate any of the objects. IF you do not care:
let first = {
a: 'John',
b: 22,
c: 'example'
}, second = {
b: 55,
d: 'demo'
}
Object.keys(first).forEach(k => first[k] = second[k] || first[k])
console.log(first)
You could use this if you use ES6
let merge = { ...first, ..._.pick(second, Object.keys(first)) }
You can use a loop over the keys in the second array. For any keys that exist in the first, overwrite the value.
let first = {
a: 'John',
b: 22,
c: 'example'
}
let second = {
b: 55,
d: 'demo'
}
for (const k in second) {
if (k in first) {
first[k] = second[k];
}
}
console.log(first);
You want to update the values of the
intersection
of the properties.
So basically something like:
Object.keys(a).forEach(prop => if(b.hasOwnProperty(prop)) a[prop] = b[prop]))
Or
_.intersection(Object.keys(a), Object.keys(b)).forEach(prop => a[prop] = b[prop])
let first = {
a: 'John',
b: 22,
c: 'example'
}
let second = {
b: 55,
d: 'demo'
}
Object.keys(second).forEach(function(key,index){
if (first.hasOwnProperty(key)) {
first[key]=second[key];
}
});
console.log(first);
With Lodash two functions MergeWith and Pick
var a = {
a: 'John',
b: 22,
f:[11,22,2],
d: {a:1,b:2,c:0},
c: 'example'
}
var b = {
b: 55,
f:[3],
d: {c:1,b:11},
}
function mergeObjects(a,b){
let common = _.pick(b, Object.keys(a));
return _.mergeWith(a, common, customizer)
}
function customizer(objValue, srcValue) {
if (_.isArray(objValue)) {
return objValue.concat(srcValue);
}
if(_.isObject(objValue)) {
return mergeObjects(objValue,srcValue)
}
}
mergeObjects(a,b)
I have const a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } }
How can I merge the object values of this object like so:
I want Result: { a:1, b: 2, c: 3}
You could assign the spreaded values.
const
a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } },
result = Object.assign({}, ...Object.values(a));
console.log(result);
You can use Object.values and reduce
const a = { _: { a: 1 }, __: { b: 2 }, ___: { c: 3 } }
let op = Object.values(a).reduce((op,inp) => ({...op,...inp}) ,{})
console.log(op)
On side note:- Keep in mind ... will make a shallow copy only if you more nested object you need to deep clone them
imagine that, we have two arrays. Each of the containing objects of different type. For example:
let first: Foo[] = [
{ a: 12, b: 'x', c: 0 },
{ a: 43, b: 'y', c: 0 }
];
let second: number[] = [11, 15];
I would like merge theirs objects in a way that I finally get one array looks like below:
let first: Foo[] = [
{ a: 12, b: 'x', c: 11 },
{ a: 43, b: 'y', c: 15 }
];
As you can see I just want to assign value from the second array to c property of object from first array.
I hope that you understand my explanation of problem. I believe in your skills, guys!
you could zip the two arrays into one,
const first: Foo[] = [
{ a: 12, b: 'x', c: 0 },
{ a: 43, b: 'y', c: 0 }
];
const second: number[] = [11, 15];
const result: Foo[] = first.map((e, i) => {
return <Foo>Object.assign({}, e, { c: second[i] });
});
As so often, Array.prototype.reduce provides a good base for an approach like e.g. this one ...
var listOfItems = [
{ a: 12, b: 'x', c: 0 },
{ a: 43, b: 'y', c: 0 }
];
var listOfValues = [11, 15];
function reassignValueToGivenKey(collector, item, idx) {
item = Object.assign({}, item); // do not mutate original reference.
item[collector.key] = collector.valueList[idx]; // reassign value.
collector.itemList.push(item); // collect processed items separately.
return collector;
}
var result = listOfItems.reduce(reassignValueToGivenKey, {
key: 'c',
valueList: listOfValues,
itemList: []
}).itemList;
console.log('listOfItems : ', listOfItems);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
I think you should do it like this...
Maybe not the best, but should work in you case :)
This is very simple...
for(var i in second){
var elem = second[i];
first[i]['c'] = elem;
}