Search code examples
javascriptarraysobjectmergelodash

Merge the last tree node into an Array using Lodash


Scenario:

const obj1 = {
  a: 100,
  b: 200,
  c: { c1: 100 }
}

const obj2 = {
  b: 250,
  c: { c1: 200 },
  d: { d1: { d1a: 400 } }
}

Desired result:

someMergeFn(obj1, obj2)

// Should return...

{
  a: [100],
  b: [200, 250],
  c: { c1: [100, 200] },
  d: { d1: { d1a: [400] } }
}


My attempt is below, but I couldn't get close to the desired result.

const obj1 = {
  a: 100,
  b: 200,
  c: { c1: 100 }
}

const obj2 = {
  b: 250,
  c: { c1: 200 },
  d: { d1: { d1a: 400 } }
}

const merged = _.mergeWith(
  obj1,
  obj2,
  (first, second) =>
    Array.isArray(first) ? first.push(second) : [first, second]
)

console.log(merged)
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>


Solution

  • Start the merge with an empty object. This will prevent the mutation of the 1st object, and would start all values as empty, in which case we'll supply an empty array as the default value for first.

    As long as the 2nd value is not an object (or array), we can assume that the 1st value is an array, and use spread (or concat) to combine them to a new array. If not, we return undefined so that _.mergeWith() would handle the merging of objects/arrays.

    const obj1 = {"a":100,"b":200,"c":{"c1":100}}
    const obj2 = {"b":250,"c":{"c1":200},"d":{"d1":{"d1a":400}}}
    
    const merged = _.mergeWith(
      {},
      obj1,
      obj2,
      (first, second) =>
        !_.isObject(second) ? [...(first || []), second] : undefined
    )
    
    console.log(merged)
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>