jiku
jiku

Reputation: 293

mergeWith for [Object]

Is there any recommended approach or function to combine the fn functionality of R.mergeWith with n list items, like R.mergeAll?

I have

const data = [
  { a: 1, b: 2, c: 0, d: { e: 3 }},
  { a: 1, c: -1 },
  { a: 1, b: 4, c: 0, d: { e: 2 }}
]

and want to sum all values by key, to return

{ a: 3, b: 6, c: -1, d: { e: 5 }}

I've tried something like

R.mapAccum((a, b) => R.mergeWith(R.sum, a, b), {}, data)

(in REPL) guessing what I'm after is a way to mergeWith the previous and current object, through some fn.

Any ideas how I could do that in a terse, pure way with a functional library? I prefer Ramda, but anything would be great.

Upvotes: 0

Views: 365

Answers (2)

Scott Sauyet
Scott Sauyet

Reputation: 50807

Ramda does not currently have a mergeDeep or mergeDeepWith function. But it's likely to be added soon. See PR 1867.

With that in place, you could simply do

R.reduce(R.mergeDeepWith(R.add), {}, data)

You can see a simulation of what this would be like in the REPL.

(You need to use add rather than sum because reduce means working with one pair of objects at a time. add is for two numbers, sum is for a list of them.)

Upvotes: 1

user6586783
user6586783

Reputation:

Assuming that you have no cyclic structures in your object, this will solve your problem.

function merge(array){
  // Returns merged array
  return mergeSubArray(array);

  // This function recursively process all sub-arrays
  function mergeSubArray(subArray){

    // Sum all properties of all objects in the array
    return subArray.reduce(function(previousObject, currentObject){

      // Get all properties of an object
      Object.keys(currentObject).forEach(function(keyOfCurrentObject){
        /*
          For all properties we need to check whether this type if number or object.
          If we encountered a number, we simply add it to previous sum.
          Otherwise, if it is an object, call this function to it.
        */

        if(typeof previousObject[keyOfCurrentObject] == 'number'){
          previousObject[keyOfCurrentObject] += currentObject[keyOfCurrentObject];
        }else{
          previousObject[keyOfCurrentObject] = mergeSubArray([previousObject[keyOfCurrentObject], currentObject[keyOfCurrentObject]]);
        }
      });

      // Returns merged objects
      return previousObject;
    });
  }
}

Upvotes: 2

Related Questions