mgicrush
mgicrush

Reputation: 53

How to merge 2 arrays with objects in one?

I have 2 arrays:

  1. [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}]

  2. [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}]

How to merge these in one array with unique objects (for unique check 'name')?

Upvotes: 0

Views: 112

Answers (6)

Redu
Redu

Reputation: 26191

It's easy if you have an Object method like Object.prototype.compare(). Lets make it.

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};

Object.prototype.compare() compares two objects for a perfect match of all properties and their values. So unlike the accepted answer we are not comparing a single property but all of them. Now it's a simple reducing task. Let's see

Object.prototype.compare = function(o){
  var ok = Object.keys(this);
  return typeof o === "object" && ok.length === Object.keys(o).length ? ok.every(k => this[k] === o[k]) : false;
};

var arr1 = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}],
    arr2 = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}],
  united = arr1.reduce((p,c) => p.find(f => f.compare(c)) ? p : p.concat(c),arr2);
console.log(JSON.stringify(united));

Upvotes: 0

Nagarjuna
Nagarjuna

Reputation: 1

var a = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}];

var b = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}];

var c = a.filter(a => b.find(b => b.name === a.name) === undefined).concat(b);

console.table(c);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386786

For a new array, you could use an object as hash table for lookup.

var array1 = [{ name: 'test', lastname: 'test', gender: 'f' }, { name: 'test1', lastname: 'test1', gender: 'f' }, { name: 'test2', lastname: 'test2', gender: 'm' }],
    array2 = [{ name: 'test21', lastname: 'test21', gender: 'f' }, { name: 'test1', lastname: 'test1', gender: 'f' }, { name: 'test2', lastname: 'test2', gender: 'm' }, { name: 'test22', lastname: 'test22', gender: 'm' }],
    result = function (a1, a2) {
        function merge(a) {
            this[a.name] = this[a.name] || r.push(a);
        }

        var t = Object.create(null),
            r = [];
        a1.forEach(merge, t);
        a2.forEach(merge, t);
        return r;
    }(array1, array2);

console.log(result);

ES6

var array1 = [{ name: 'test', lastname: 'test', gender: 'f' }, { name: 'test1', lastname: 'test1', gender: 'f' }, { name: 'test2', lastname: 'test2', gender: 'm' }],
    array2 = [{ name: 'test21', lastname: 'test21', gender: 'f' }, { name: 'test1', lastname: 'test1', gender: 'f' }, { name: 'test2', lastname: 'test2', gender: 'm' }, { name: 'test22', lastname: 'test22', gender: 'm' }],
    result = function (a1, a2) {
        var t = Object.create(null),
            r = [],
            m = a => t[a.name] = t[a.name] || r.push(a);
        a1.forEach(m);
        a2.forEach(m);
        return r;
    }(array1, array2);

console.log(result);

Upvotes: 0

Mulan
Mulan

Reputation: 135406

A combination of filter and find will work

var a = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}];

var b = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}];

var c = a.filter(a => b.find(b => b.name === a.name) === undefined).concat(b);

console.table(c);

enter image description here


You could also make a generic uniqueByKey function

var uniqueByKey = (key, xs)=>
  xs.reduce((ys,x)=>
    ys.find(y=> y[key] === x[key]) === undefined
      ? ys.concat([x])
      : ys,
    []);

var a = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}];

var b = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}];

var c = uniqueByKey('name', a.concat(b));

console.table(c);

enter image description here


If you're dealing with particularly large datasets, using a Set cache instead of Array.prototype.find might be better.

var uniqueByKey = (key, xs)=>
  xs.reduce(([set, ys], x)=>
    set.has(x[key])
      ? [set, ys]
      : [set.add(x[key]), ys.concat([x])]
    , [new Set, []]
  ) [1];

var a = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}];

var b = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}];

var c = uniqueByKey('name', a.concat(b));

console.table(c);

enter image description here

Upvotes: 4

yankee
yankee

Reputation: 40850

What you can do to check duplicate elements the fastest method is to add all elements to an object with the name that you want as key, because accessing the keys is very fast:

var unified = {},
    unifiedArray = [],
    first = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}],
    second = [{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}],
    addToUnified = function(obj) {
        if (unified[obj.name]) {
            alert('duplicate detected!\n' + JSON.stringify(obj) + '\n' + ' has same name as\n'  + JSON.stringify(unified[obj.name]));
        } else {
            unifiedArray.push(obj);
            unified[obj.name] = obj;
        }
    }
first.forEach(addToUnified);
second.forEach(addToUnified);

If you just want to get a report you don't need the unifiedArray. If you don't need the report just eliminate the alert

Upvotes: 0

Vladu Ionut
Vladu Ionut

Reputation: 8193

var arr1 = [{name:'test', lastname: 'test', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'}]
var arr2 = [{name:'test', lastname: 'test', gender:'f'},{name:'test21', lastname: 'test21', gender:'f'},{name:'test1', lastname: 'test1', gender:'f'},{name:'test2', lastname: 'test2', gender:'m'},{name:'test22', lastname: 'test22', gender:'m'}]

var newArray =arr1.concat(arr2);
var unique = {};
var result = [];


newArray.forEach(function (elem) {
  if (!unique[elem.name]) {
    result.push(elem);
    unique[elem.name] = true;
  }
});
console.log(result);
document.write(JSON.stringify(result));

Upvotes: 1

Related Questions