Merge two javascript objects adding shared property values

I have two or more javascript objects. I want to combine them by adding the values โ€‹โ€‹of common properties, and then sort them in descending order of values.

eg.

var a = {en : 5,fr: 3,in: 9} var b = {en: 8,fr: 21,br: 8} var c = merge(a,b) 

c should look like this:

 c = { fr: 24, en: 13, in:9, br:8 } 

i.e. both merge objects, the values โ€‹โ€‹of the shared keys are added, and then the keys are sorted.

Here is what I tried:

 var a = {en : 5,fr: 3,in: 9} var b = {en: 8,fr: 21,br: 8} c = {} // copy common values and all values of a to c for(var k in a){ if(typeof b[k] != 'undefined'){ c[k] = a[k] + b[k] } else{ c[k] = a[k]} } // copy remaining values of b (which were not common) for(var k in b){ if(typeof c[k]== 'undefined'){ c[k] = b[k] } } // Create a object array for sorting var arr = []; for(var k in c){ arr.push({lang:k,count:c[k]}) } // Sort object array arr.sort(function(a, b) { return b.count - a.count; }) 

but I do not think that is good. So many loops :( It would be nice if someone could provide less dirty and good code.

+9
source share
4 answers

It is not possible to sort the properties of an object, however you can sort the array:

 var merged = $.extend({}, a); for (var prop in b) { if (merged[prop]) merged[prop] += b[prop]; else merged[prop] = b[prop]; } // Returning merged at this point will give you a merged object with properties summed, but not ordered. var properties = []; for (var prop in merged) { properties.push({ name: prop, value: merged[prop] }); } return properties.sort(function(nvp1, nvp2) { return nvp1.value - nvp2.value; }); 
+2
source

EDIT - I modified the script, this combines the properties if they are of the same type: numbers are summed, strings are concatenated and objects are merged recursively. I did not enable sorting because (quoting this answer Sorting a JavaScript object by property value )

JavaScript objects are not ordered by definition (see ECMAScript Language Specification, Section 8.6). The language specification does not even guarantee that if you go through the properties of an object twice in a row, they will come out in the same order as the second time.

If you need things to order, use the array and the Array.prototype.sort Method.

 function is_object(mixed_var) { if (Object.prototype.toString.call(mixed_var) === '[object Array]') { return false; } return mixed_var !== null && typeof mixed_var == 'object'; } function merge(a, b) { var cache = {}; cache = unpackObject(a, cache); cache = unpackObject(b, cache); return cache; } function unpackObject(a, cache) { for (prop in a) { if (a.hasOwnProperty(prop)) { if (cache[prop] === undefined) { cache[prop] = a[prop]; } else { if (typeof cache[prop] === typeof a[prop]) { if (is_object(a[prop])) { cache[prop] = merge(cache[prop], a[prop]); } else { cache[prop] += a[prop]; } } } } } return cache; } var a = { en: 5, fr: 3, in : 9, lang: "js", object: {nestedProp: 6} } var b = { en: 8, fr: 21, br: 8, lang: "en", object: {nestedProp: 1, unique: "myne"} } var c = merge(a, b); 

fiddle here http://jsfiddle.net/vyFN8/1/

+1
source

Here is my attempt, which is recursive for nested objects - https://gist.github.com/greenafrican/19bbed3d8baceb0a15fd

 // Requires jQuery // Merge nested objects and if the properties are numbers then add them together, else // fallback to jQuery.extend() result function mergeObjectsAdd(firstObject, secondObject) { var result = $.extend(true, {}, firstObject, secondObject); for (var k in result) { if ("object" === typeof result[k]) { firstObject[k] = firstObject[k] || {}; secondObject[k] = secondObject[k] || {}; result[k] = mergeObjectsAdd(firstObject[k], secondObject[k]); } else { firstObject[k] = firstObject[k] || 0; secondObject[k] = secondObject[k] || 0; result[k] = ("number" === typeof firstObject[k] && "number" === typeof secondObject[k]) ? (firstObject[k] + secondObject[k]) : result[k]; } } return result; } 
+1
source

In ES2015 +, the properties of the object are ordered (first by increasing numeric keys, then by the order of insertion of non-numeric keys). This is guaranteed by the specification if you use one of the methods for which the iteration order is specified (for example, Object.getOwnPropertyNames ). Methods for which the iteration order is not specified (for example, Object.keys and for..in ) are not guaranteed to have any particular order, but pretty much all modern environments still iterate in the same predictable order.

But you must be sure that none of the properties is numeric (otherwise they will come first, before the non-numeric properties, regardless of the insertion order).

Use reduce to iterate over each object and create or add to the same property on the battery. Then, sort the object records, and use Object.fromEntries to convert it to an object with sorted properties. No jQuery needed:

 var a = {en : 5,fr: 3,in: 9} var b = {en: 8,fr: 21,br: 8} console.log(merge(a, b)); function merge(...objects) { const merged = objects.reduce((a, obj) => { Object.entries(obj).forEach(([key, val]) => { a[key] = (a[key] || 0) + val; }); return a; }, {}); return Object.fromEntries( Object.entries(merged).sort( (a, b) => b[1] - a[1] ) ); } 

+1
source

All Articles