Having a set of utility functions on hand can greatly simplify tackling this type of problem.
The approach I take is to create the following function:
const combine = reduce (mergeWith (concat)) ({})
This function is built using my utility functions reduce
, concat
, and mergeWith
. Using it is as straightforward as:
combine (a) //=> {26: [0, 0, 0], 27: [100, 100, 100], 28: [0, 0, 0]}
const reduce = (f) => (init) => (xs) => xs .reduce ((a, x) => f (a, x), init)
const concat = (a) => (b) => a .concat (b)
const mergeWith = (f) => (a, b) => Object .fromEntries (
[... new Set ([... Object .keys (a), ... Object .keys (b)])] .map (
(k) => [k, k in a ? (k in b ? f (a [k]) (b [k]) : a [k]) : b [k]]
)
)
const combine = reduce (mergeWith (concat)) ({})
const a = [{26: [0], 27: [100], 28: [0]}, {26: [0], 27: [100], 28: [0]}, {26: [0], 27: [100], 28: [0]}]
console .log (combine (a))
.as-console-wrapper {max-height: 100% !important; top: 0}
reduce
and concat
essentially convert array methods into pure functions.1 They are fully curried, making it easier to compose functions by calling them with multiple arguments instead of using method chaining.
mergeWith
function performs a shallow merge between two objects, utilizing a provided function when keys match in both objects, and using the supplied property otherwise.
By setting up these utility functions in advance, writing the solution becomes quite straightforward. We configure mergeWith
with concat
and pass them along with an empty object to reduce
.
const combine = reduce (mergeWith (concat)) ({})
1reduce
does not provide all parameters to the transformation function that Array.prototype.reduce
does. This design choice has its reasons, but if desired, we could simplify the implementation to const reduce (f) => (init) => (xs) => xs .reduce (f, init)
.