Problem
In the slow progress of the project that generated my all-but-tumbleweed previous question I’ve needed to make sum-unions (any better term?) of simple objects where key:value is sizeClass:tally
— I need the union of all sizeClasses
, summing their values where they’re the same. I came up with this and I wonder whether anyone sees anything terrible about it or has a slicker way.
function mashObj(objA,objB) {
var objC = {};
var [ak,av] = deval(objA);
var [bk,bv] = deval(objB);
for (var i=0;i<ak.length;i++) {
objC[ak[i]] = av[i];
}
for (i=0;i<bk.length;i++) {
objC[bk[i]] = (objC[bk[i]] || 0) + bv[i];
}
return objC;
}
function deval(obj) {
var ks = [];
var vs = [];
for (var k in obj) {
ks.push(k);
vs.push(Math.round(obj[k]));
}
return [ks, vs];
}
These functions are purpose-built, plenty of assumption about what’s coming in, so there’s been no attempt at generalizing. I go through deval()
rather than doing a for..in
because I also need to preserve the original two objects — I’ve been getting into a lot of trouble with the spooky-manipulation-at-a-distance problem.
By “sum-union” all I mean is that I might have something like:
plot1 = {2:4, 5:12, 7:3};
plot2 = {2:1, 4:3, 5:3};
// and what I want to get is
total == {2:5, 4:3, 5:15, 7:3};
I assume that somewhere in math, logic or CS, probably all three, there’s a proper term for this.
Solution
Since you’re using ES2015 destructuring assignments you can use Set
and spread:
function mashObj(a, b) {
var sum = {};
new Set([...Object.keys(a), ...Object.keys(b)])
.forEach(k => sum[k] = Math.round(a[k]||0) + Math.round(b[k]||0));
return sum;
}
Just a few improvement as the code is quite small.
You can shorten your deval()
to this:
function deval(obj) {
var arr = $.map(obj, function(value) {
return value;
});
return [Object.keys(obj), arr];
}
plot1 = {2:4, 5:12, 7:3};
plot2 = {2:1,4:3,5:3};
console.log(deval(plot1));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
There is an Object.keys()
that creates an array of all the keys of an object. Note, there is also an Object.values()
, which is an experimental technology with little support in all browsers.
In place of that, I used a map()
as shown in this example Get object values without looping.