Anirban
Anirban

Reputation: 589

Union of 2 arrays using lodash

I have the following 2 arrays:

    arr1 = [
            {
                "key1": "Value1"
            },
            {
                "key2": "Value2"
            },
            {
                "key3": "Test3"
            },
            {
                "key4": "Test4"
            },
            {
                "key5": "Test5"
            },
            {
                "key6": "Test6"
            },
            {
                "key7": "Test7"
            }
        ]

And the second array is

    arr2 = [
            {
                "key3": "Value3-changed"
            },
            {
                "key6": "Value6-changed"
            }

        ]

Now once I join the 2 arrays the result would be

   resultArr = [
        {
            "key1": "Value1"
        },
        {
            "key2": "Value2"
        },
        {
            "key3": "Value3-changed"
        },
        {
            "key4": "Test4"
        },
        {
            "key5": "Test5"
        },
        {
            "key6": "Value6-changed"
        },
        {
            "key7": "Test7"
        }
    ]

I saw the solution for Lodash union of arrays of objects. But as for my case, the keys are different. Any, pointers on solving this issue? I was trying to use lodash _.unionBy and then _.uniqWith but not getting the desired result.

Thanks, Andy

Upvotes: 2

Views: 3774

Answers (6)

iDaN5x
iDaN5x

Reputation: 706

If you have access to the ... spread operator:

map(chunk(toPairs(assign(...arr1, ...arr2))), fromPairs)

Otherwise:

map(chunk(toPairs(spread(assign)(concat(arr1, arr2)))), fromPairs)

Which is ugly but does the job.


Lodash plugins

_.mixin({
  'assignPairsChunkAndMapObjects' : function(arr1, arr2) {
    return _.map(_.chunk(_.toPairs(_.assign(...arr1, ...arr2))), _.fromPairs);
  },
  'assignPairsChunkAndMapObjectsChained' : function(arr1, arr2) {
    return _.chain(_.assign(...arr1, ...arr2)).toPairs().chunk().map(_.fromPairs).value();
  }
});

Upvotes: 1

Narendra Jadhav
Narendra Jadhav

Reputation: 10262

You can also use map and find method of array.

In ES5

var arr1 = [{
    "key1": "Value1"
  }, {
    "key2": "Value2"
  }, {
    "key3": "Test3"
  }, {
    "key4": "Test4"
  }, {
    "key5": "Test5"
  }, {
    "key6": "Test6"
  }, {
    "key7": "Test7"
  }],

  arr2 = [{
    "key3": "Value3-changed"
  }, {
    "key6": "Value6-changed"
  }],

  key = '';

var result = arr1.map(function(item) {
  key = Object.keys(item)[0];
  return arr2.find(function(v) {
    return v[key]
  }) || item;
});

console.log(result);

In ES6

const arr1 = [{
    "key1": "Value1"
  }, {
    "key2": "Value2"
  }, {
    "key3": "Test3"
  }, {
    "key4": "Test4"
  }, {
    "key5": "Test5"
  }, {
    "key6": "Test6"
  }, {
    "key7": "Test7"
  }],

  arr2 = [{
      "key3": "Value3-changed"
    }, {
      "key6": "Value6-changed"
    }

  ];

let result = arr1.map(item => {
  let key = Object.keys(item)[0];
  return arr2.find(v => v[key]) || item;
});

console.log(result);

Upvotes: 0

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48693

You can create a mixin to iterate over the first array and merge it with the second one.

_.mixin({
  'mergeObjectList' : function(arr1, arr2) {
    return _.map(arr1, function(obj) {
      Object.keys(obj).forEach(key => {
        var found = _.find(arr2, x => Object.keys(x).indexOf(key) > -1);
        if (found != null) {
          return _.merge(obj, found);
        }
      });
      return obj;
    });
  }
});

var arr1 = [
  { "key1": "Value1" },
  { "key2": "Value2" },
  { "key3": "Test3" },
  { "key4": "Test4" },
  { "key5": "Test5" },
  { "key6": "Test6" },
  { "key7": "Test7" }
];

var arr2 = [
  { "key3": "Value3-changed" },
  { "key6": "Value6-changed" }
];

var arr3 = _.mergeObjectList(arr1, arr2);

document.body.innerHTML = JSON.stringify(arr3, null, 4);
body { font-family: monospace; white-space: pre; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>

Upvotes: 0

funkizer
funkizer

Reputation: 4897

No lodash needed. First reduce both arrays to a single object, where keys coming later overwrite any previously set values:

const obj = [...arr1, ...arr2].reduce((acc,cur) => Object.assign(acc, cur), {});
// {key1: value1, ...}

Edit, even simpler:

const obj = Object.assign({}, ...arr1, ...arr2);

Then map the keys back to an array of objects:

const resultArray = Object.keys(obj)
   .sort() // if alphanumeric order of keys matters to you
   .map(key => { const o={}; o[key]=obj[key]; return o;});

Upvotes: 2

brk
brk

Reputation: 50336

With native javascript you can achieve the same using for ..in & map function

var arr1 = [{
    "key1": "Value1"
  },
  {
    "key2": "Value2"
  },
  {
    "key3": "Test3"
  },
  {
    "key4": "Test4"
  },
  {
    "key5": "Test5"
  },
  {
    "key6": "Test6"
  },
  {
    "key7": "Test7"
  }
]
var arr2 = [{
    "key3": "Value3-changed"
  },
  {
    "key6": "Value6-changed"
  }

];
// get object keys from both
var getArr2Keys = arr2.map(function(items) {
  for (let keys in items) {
    return keys;
  }
});

var getArr1Keys = arr1.map(function(items) {
  for (let keys in items) {
    return keys;
  }
});


// iterate over the newly created object and check if the key matched
getArr2Keys.forEach(function(itemArr2, index) {
  var x = getArr1Keys.findIndex(function(itemArr1) {
    return itemArr2 === itemArr1;
  })
  // replace the key value of arr1 with value from arr2
  arr1[x][itemArr2] = arr2[index][itemArr2]

})

console.log(arr1)

Upvotes: 0

Pac0
Pac0

Reputation: 23174

You can do this without lodash like this :

(pushes new objects, or update existing one.

let arr1 = [
    {
        "key1": "Value1"
    },
    {
        "key2": "Value2"
    },
    {
        "key3": "Test3"
    },
    {
        "key4": "Test4"
    },
    {
        "key5": "Test5"
    },
    {
        "key6": "Test6"
    },
    {
        "key7": "Test7"
    },
]

let arr2 = [
    {
        "key3": "Value3-changed"
    },
    {
        "key6": "Value6-changed"
    },
    {
        "key10": "Value10-new"
    },
]

for (let obj of arr2) {
    let keyName = Object.keys(obj)[0];
    let existingObject = arr1.find(x => Object.keys(x)[0] === keyName );
    
    if (existingObject) {
        // object with same key exists. So we update it.
        existingObject[keyName] = obj[keyName];
    } else {
        // key was not found, this is a new object, let's add it.
        arr1.push(obj);
    }
}

console.log(arr1)

There is probably a more elegant way to do that, of course.

Upvotes: 1

Related Questions