Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I uniquely union two array of objects?

I am trying to merge two arrays of objects without using the unionBy method from lodash.

Currently I have the following code working perfectly:

var array1 = [
 { a: 1, b: 'first'},
 { a: 2, b: 'second'}
];

var array2 = [
 { a: 3, b: 'third'},
 { a: 1, b: 'fourth'}
];

var array3 = __.unionBy(array2, array1, 'a');

This outputs:

[
  {
    "a": 3,
    "b": "third"
  },
  {
    "a": 1,
    "b": "fourth"
  },
  {
    "a": 2,
    "b": "second"
  }
]

This is the desired result but I can't use unionBy in my current work environment, so I'm looking for a result that uses either native JS or other lodash methods 3.6.0 or lower.

like image 624
zeckdude Avatar asked Jan 21 '18 19:01

zeckdude


People also ask

How do you merge an array of objects into a single object?

Use the Array. We can use the JavaScript array reduce method to combine objects in an array into one object. We have the arr array which we want to combine into one object. To do that, we call reduce with a callback that returns an object with obj spread into the returned object. And we add the item.

How do you merge two arrays of objects in react JS?

Use the spread syntax (...) to merge arrays in React, e.g. const arr3 = [...arr1, ...arr2] . The spread syntax is used to unpack the values of two or more arrays into a new array. The same approach can be used to merge two or more arrays when setting the state.


3 Answers

Concat and use Array#filter with a helper object to remove duplicates:

var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

var array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

var result = array2.concat(array1).filter(function(o) {  
  return this[o.a] ? false : this[o.a] = true;
}, {});

console.log(result);

If ES6 is an option you can use a Set instead of the helper object:

const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

const result = array2.concat(array1).filter(function(o) {  
  return this.has(o.a) ? false : this.add(o.a);
}, new Set());

console.log(result);

If you want to use an arrow function, you can't use the thisArg of Array.filter() to bind the Set as the this of the function (you can't bind this to arrow functions). You can use a closure instead (attribute for the method goes to @NinaScholz).

const array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}];

const array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

const result = [...array2, ...array1]
  .filter((set => // store the set and return the actual callback
      o => set.has(o.a) ? false : set.add(o.a)
    )(new Set()) // use an IIFE to create a Set and store it set
  );

console.log(result);
like image 125
Ori Drori Avatar answered Oct 18 '22 00:10

Ori Drori


You could take a Set for filtering to get unique values.

var array1 = [{ a: 1, b: 'first' }, { a: 2, b: 'second' }],
    array2 = [{ a: 3, b: 'third' }, { a: 1, b: 'fourth' }],
    s = new Set,
    array3 = array2.map(o => (s.add(o.a), o)).concat(array1.filter(o => !s.has(o.a)));

console.log(array3);
like image 1
Nina Scholz Avatar answered Oct 17 '22 23:10

Nina Scholz


You can use an ES6 Map for this. Construct it with the data, keyed by the a property value, and then take the values out of the Map again:

var array1 = [{"a":1,"b":"first"},{"a":2,"b":"second"}],
    array2 = [{"a":3,"b":"third"},{"a":1,"b":"fourth"}];

var result = [...new Map([...array1,...array2].map( o => [o.a, o] )).values()];

console.log(result);
like image 1
trincot Avatar answered Oct 17 '22 22:10

trincot