JavaScript - merge two arrays of objects and de-duplicate based on property value
Solution 1
Using a double for loop and splice you can do it like so:
for(var i = 0, l = origArr.length; i < l; i++) {
for(var j = 0, ll = updatingArr.length; j < ll; j++) {
if(origArr[i].name === updatingArr[j].name) {
origArr.splice(i, 1, updatingArr[j]);
break;
}
}
}
Example here
Solution 2
I came here looking for exactly this, saw @Gruff Bunny 's technique and wondered if 'lodash' wouldn't perhaps be a superior option even to 'underscore'?
Lo and behold :
let result = _.unionBy(updatingArr, origArr, 'name');
Solution 3
You could use Array#map
in combination with Array#reduce
var origArr = [{ name: 'Trump', isRunning: true }, { name: 'Cruz', isRunning: true }, { name: 'Kasich', isRunning: true }],
updatingArr = [{ name: 'Cruz', isRunning: false }, { name: 'Kasich', isRunning: false }],
NEWArr = origArr.map(function (a) {
return this[a.name] || a;
}, updatingArr.reduce(function (r, a) {
r[a.name] = a;
return r;
}, Object.create(null)));
document.write('<pre>' + JSON.stringify(NEWArr, 0, 4) + '</pre>');
UPDATE 2022
Using an object with name
as hash and mapping the original array by taking the update from hash table or the original object.
const
origArr = [{ name: 'Trump', isRunning: true }, { name: 'Cruz', isRunning: true }, { name: 'Kasich', isRunning: true }],
updatingArr = [{ name: 'Cruz', isRunning: false }, { name: 'Kasich', isRunning: false }],
updates = Object.fromEntries(updatingArr.map(o => [o.name, o])),
result = origArr.map(o => updates[o.name] || o);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another approach by using Map
.
This approach works for objects who are only in the updating array as well.
const
origArr = [{ name: 'Trump', isRunning: true }, { name: 'Cruz', isRunning: true }, { name: 'Kasich', isRunning: true }],
updatingArr = [{ name: 'Cruz', isRunning: false }, { name: 'Kasich', isRunning: false }],
result = Array.from([...origArr, ...updatingArr]
.reduce((m, o) => m.set(o.name, o), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Solution 4
const origArr = [
{name: 'Trump', isRunning: true},
{name: 'Cruz', isRunning: true},
{name: 'Kasich', isRunning: true}
];
const updatingArr = [
{name: 'Cruz', isRunning: false},
{name: 'Kasich', isRunning: false}
];
let hash = {};
for(let i of origArr.concat(updatingArr)) {
if(!hash[i]) {
hash[i.name] = i;
}
}
let newArr = [];
for(let i in hash) {
newArr.push(hash[i])
}
console.log(newArr);
Solution 5
You can give this a try.
var origArr = [
{name: 'Trump', isRunning: true},
{name: 'Cruz', isRunning: true},
{name: 'Kasich', isRunning: true}
];
var updatingArr = [
{name: 'Cruz', isRunning: false},
{name: 'Kasich', isRunning: false}
];
var origLength = origArr.length;
var updatingLength = updatingArr.length;
//Traverse the original array and replace only if the second array also has the same value
for(i = origLength-1; i >= 0; i--) {
for(j = updatingLength -1; j >= 0; j--) {
if(origArr[i].name === updatingArr[j].name) {
origArr[i] = updatingArr[j];
}
}
}
console.log(origArr);
Sean O
''Superb Parodist'' -- The New York Times. Director of IT. Web application developer. Digital craftsman & curator.
Updated on December 25, 2021Comments
-
Sean O over 2 years
I want to update (replace) the objects in my array with the objects in another array. Each object has the same structure. e.g.
var origArr = [ {name: 'Trump', isRunning: true}, {name: 'Cruz', isRunning: true}, {name: 'Kasich', isRunning: true} ]; var updatingArr = [ {name: 'Cruz', isRunning: false}, {name: 'Kasich', isRunning: false} ]; // desired result: NEWArr = [ {name: 'Trump', isRunning: true}, {name: 'Cruz', isRunning: false}, {name: 'Kasich', isRunning: false} ];
I've tried concat() & Underscore's
_.uniq
function, but it always dumps the newer object & returns, essentially, the original array.Is there a way to overwrite (replace)
origArr
with the objects inupdatingArr
-- matching on thename
property?-
spaceman about 8 yearsIs that what you are meaning? jsfiddle.net/4p98w3su not sure I understood the question.
-
Sean O about 8 yearsAll good answers here; I like yours the best, using splice. If you want to convert this to an Answer, I'll mark as Accepted. Thanks.
-
spaceman about 8 yearsI put it as an answer, I think it is also faster than the methods involving map & reduce. I was getting about twice the speed when running it millions of times in a while loop.
-
-
Manish M Demblani about 8 yearstraversal is done in the reverse order since it is least time consuming, according to tests conducted by jspref
-
bharadhwaj over 2 yearsThis will only work for the flat lists. Won't work for this scenario.
-
Julian over 2 yearsWhile Underscore is much smaller than Lodash, you can still get the same result in a single line using
concat
,groupBy
,map
andlast
. You can also addunionBy
to Underscore in just five lines of code. See this answer. -
Julian over 2 yearsSingle-line pure Underscore solution here: stackoverflow.com/a/70474201/1166087
-
Julian over 2 yearsMore compact and efficient solution using Underscore, which also adds new entries on update: stackoverflow.com/a/70474201/1166087
-
Julian over 2 yearsWhile not asked in the original question, Backbone arguably has the best solution for updating data. See stackoverflow.com/a/70474027/1166087.
-
A. Rabus almost 2 yearsi need some explainer for this, please... :/
-
Nina Scholz almost 2 years@A.Rabus, this code is acutally using a hash table for udate values and maps either the updates values or the original value. actually, i would separate the two steps into two parts and do not use
this
anymore.