Merging Javascript Objects
Solution 1:
I posted my comment with the idea that someone else would post a more serious answer, but since nobody came along, I guess I’ll describe how you might go about doing it seriously.
First, you’ll have to know how to merge one object into another. It’s not too difficult, but you do have to know how to use for
-in
, which isn’t frequently taught, and it’s usually a good idea to include a hasOwnProperty
check which is even less-frequently taught:
function mergeObjectInto(source, target) {
for(var property in source) {
if(Object.prototype.hasOwnProperty.call(source, property)) {
target[property] = source[property];
}
}
}
Essentially, this enumerates over all properties of the source. If that property is an own property of the object—that is, it’s not something it inherited from its prototype—we copy that property over to the target.
Now, to model the kind of operation you want to do, we can decompose it down into a simpler operation: given an existing array, put another object in that array, merging if necessary. A naïve implementation might look like this:
function mergeObjectIntoArray(existingArray, newObject) {
// Search for an already-existing object in the array that shares the same
// value for the `date' property.
var correspondingExistingObject = null;
for(var index = 0, length = existingArray.length; index < length; index++) {
if(existingArray[index].date === newObject.date) {
correspondingExistingObject = existingArray[index];
break;
}
}
if(correspondingExistingObject !== null) {
// If we found an existing object that corresponds to our new object, just
// merge any new properties in rather than adding a new item to the array.
mergeObjectInto(newObject, correspondingExistingObject);
}else{
// Otherwise, bite the bullet and add the new object since there's nothing
// we can usefully merge into.
existingArray.push(newObject);
}
}
You could then implement the sort of merge operation you wanted by calling this function in a loop. But if you work it out, that’s going to have quadratic time, which will be an issue if this has to work on a large number of data items. As it happens, there is a way you can work around it. If we sort items into a hash-table-like structure keyed by date
property as we go, we can check in constant time whether we have an object with that date or not, and if so, merge into it; otherwise, add it. That leads to a very reasonable linear time for the entire algorithm.
One complication is that until recently with ECMAScript 6, JavaScript hasn’t really had a real “hash table”. The closest thing we have are objects, which can only have string keys. That’ll work for us, but we do need to exercise some caution: for better or worse, browser vendors have created some property names with special significance, like __proto__
, that we really don’t want to step on, so we’ll prefix our keys with some character that prevents any clashes with built-in names. I chose #
for this purpose. (#
is a hash, and it’s a hash-table.)
In code, here’s how that would work out, this time the function taking an entire array of items and merging all objects with duplicate date
property values:
function mergeDuplicateObjectsInArray(array) {
var result = [];
var objectsByDate = {};
for(var index = 0, length = array.length; index < length; index++) {
var object = array[index];
var hashKey = '#' + object.date;
var mergeTarget;
if(Object.prototype.hasOwnProperty.call(objectsByDate, hashKey)) {
// Already have an object by that date; we ought to merge into that.
mergeObjectInto(object, objectsByDate[object.date]);
}else{
// No object by that date yet; we'll be the first.
result.push(object);
objectsByDate[object.date] = object;
}
}
return result;
}
This still misses out on one last thing: it’s only merging objects within a single array, not two different arrays. But it will do what you want if you created a single array with the objects of both arrays, e.g. myVar1.concat(myVar2)
. In any case, you could also modify the for
loop in it to loop over an array of arrays, and then loop over the objects in those arrays, which is what my golfed version did. The other difference to the golfed version is the golfed version avoids modifying the original arrays or objects, which would be a relatively simple modification of the unobfuscated version: to make a copy, just merge into an empty object.
Hopefully that clears things up.
Post a Comment for "Merging Javascript Objects"