I have two or more javascript objects. I want to merge them adding values of mon properties and then sort them in descending order of values.
e.g.
var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
var c = merge(a,b)
c
should then be like this:
c = {
fr: 24,
en: 13,
in:9,
br:8
}
i.e. both objects are merge, values of mon keys are added and then keys are sorted.
Here's what I've tried:
var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
c = {}
// copy mon 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 mon)
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 dont think its good. So many loops :( It would be nice if someone can provide a less messy and good code.
I have two or more javascript objects. I want to merge them adding values of mon properties and then sort them in descending order of values.
e.g.
var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
var c = merge(a,b)
c
should then be like this:
c = {
fr: 24,
en: 13,
in:9,
br:8
}
i.e. both objects are merge, values of mon keys are added and then keys are sorted.
Here's what I've tried:
var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
c = {}
// copy mon 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 mon)
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 dont think its good. So many loops :( It would be nice if someone can provide a less messy and good code.
Share Improve this question edited Feb 7, 2012 at 11:44 Jashwant asked Feb 7, 2012 at 10:54 JashwantJashwant 29k16 gold badges75 silver badges108 bronze badges 7- see this link api.jquery./jQuery.merge – mgraph Commented Feb 7, 2012 at 10:57
- @Dogbert So far I am here, pastebin./VQehhcri – Jashwant Commented Feb 7, 2012 at 11:02
- Plain objects are not sorted. You'll need to go for an array to achieve sorting. – Chris Morgan Commented Feb 7, 2012 at 11:25
- None of the answers below is working but I have found a way, but I dont think its good. Please look into that and optimise the code. Here's the pastebin. pastebin./nEKB7zAc – Jashwant Commented Feb 7, 2012 at 11:35
- 1 @Jashwant your code for sorting is ok, as long as the porpoerties are numbers – Nicola Peluchetti Commented Feb 7, 2012 at 11:59
4 Answers
Reset to default 3In ES2015+, object properties are ordered (first by ascending numeric keys, then by insertion order for non-numeric keys). This is guaranteed by the specification if you use one of the methods for which iteration order is specified (like Object.getOwnPropertyNames
).
In ES2020+, the methods for which enumeration order used to be unspecified are now specified (though environments have been following it for ages anyway).
But you have to be sure that none of the properties are numeric (otherwise, they'll e first, before non-numeric properties, no matter the insertion order).
Use reduce
to iterate over each object and create or add to the same property on the accumulator. Then, sort
the object's entries, and use Object.fromEntries
to transform it into an object with sorted properties. No need for jQuery:
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]
)
);
}
It is not possible to sort the properties of an object, you can however sort an 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;
});
EDIT - i modified the script, this merges the properties if they are of the same type: numbers are summed, strings are concatenated and objects are recursively merged. I didn't include sorting because (quoting this answer Sorting JavaScript Object by property value)
JavaScript objects are unordered by definition (see the ECMAScript Language Specification, section 8.6). The language specification doesn't even guarantee that, if you iterate over the properties of an object twice in succession, they'll e out in the same order the second time.
If you need things to be ordered, use an 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/vyFN8/1/
Here is my attempt, which is recursive for nested objects - https://gist.github./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;
}