'Union of Array of Objects in JavaScript?

So after searching the interwebz for a few hours I have not found the solution I am looking for.

I have two arrays that contain game objects with a lot of information inside. (e.g. title, slug, thumbnail, summary, genre, release date...).

The Array 1 is a collection of objects that match user's interests specified during the registration.

The Array 2 is a collection of objects that match purchased games of similar users. (Similar users are those that share common interests)

Problem: It is possible, and what is happening in my case, there are two identical games - the game in Array 1 is also in Array 2. In the first array the game is there because it matches user's interests. In the second array the game is there because a similar user has bought that game.

Question: Underscore.js has a nice little function union() http://underscorejs.org/#union that gives you a union of two arrays, but it does not work with an array of objects, only on primitive values. How could I make it work give me a union of array of objects?



Solution 1:[1]

You can do it using the underscore way:

// collectionUnion(*arrays, iteratee)
function collectionUnion() {
    var args = Array.prototype.slice.call(arguments);
    var it = args.pop();

    return _.uniq(_.flatten(args, true), it);
}

It just an improvment of the original function _.union(*arrays), adding an iteratee to work collection (array of object).

Here how to use it:

var result = collectionUnion(a, b, c, function (item) {
    return item.id;
});

The original function which is just working with array, looks like that:

_.union = function() {
  return _.uniq(flatten(arguments, true, true));
};

And in bonus a full example:

// collectionUnion(*arrays, iteratee)
function collectionUnion() {
    var args = Array.prototype.slice.call(arguments);
    var it = args.pop();

    return _.uniq(_.flatten(args, true), it);
}

var a = [{id: 0}, {id: 1}, {id: 2}];
var b = [{id: 2}, {id: 3}];
var c = [{id: 0}, {id: 1}, {id: 2}];

var result = collectionUnion(a, b, c, function (item) {
    return item.id;
});

console.log(result); // [ { id: 0 }, { id: 1 }, { id: 2 }, { id: 3 } ]

Solution 2:[2]

Set (ES6/ES2015) will help you.

const info1 = {id: 1}
const info2 = {id: 2}
const info3 = {id: 3}

const array1 = [info1, info2]
const array2 = [info1, info3]

const union = [...new Set([...array1, ...array2])]

console.log(union)

Solution 3:[3]

jQuery has the method extend:

$.extend(true, object1, object2);

Solution 4:[4]

Using underscore extend, you can do:

var objects = [{ bar : 1, nuts : 2} , {foo : 3, nuts : 4}]
_.extend.apply(this,objects)

If the list can be empty, make sure to append an empty object to it.

Solution 5:[5]

Here is better solution

function arrayUnion() {
    var args = Array.prototype.slice.call(arguments);
    var it = args.pop();

    return _.uniq(_.flatten(args, true), it);
}

var a = [{id: 0}, {id: 1}, {id: 2}];
var b = [{id: 2}, {id: 3}];
var c = [{id: 0}, {id: 1}, {id: 2}];

var result = arrayUnion(a, b, c, function (item) {
    return item.id;
});

console.log(result); 

Solution 6:[6]

const a=[
  {
    id:1,
    label:"mnbmnbm1"
  },
  {
    id:2,
    label:"mnbmnbm2"
  },
  {
    id:3,
    label:"mnbmnbm3"
  }
];
const b=[
  {
    id:1,
    label:"mnbmnbm1"
  },
  {
    id:2,
    label:"mnbmnbm2"
  },
  {
    id:4,
    label:"mnbmnbm5"
  }
];
const c=[
  {
    id:1,
    label:"mnbmnbm1"
  },
  {
    id:5,
    label:"mnbmnbm5"
  },
  {
    id:6,
    label:"mnbmnbm6"
  }
];

function arrayUnion(...args){
  return arrayUnique(flatten(...args));
}

function flatten(...args){
  return args.reduce((acc,cur)=>{
     if(Array.isArray(acc) && Array.isArray(cur)){
        acc=[...acc,...cur];
        return acc;
     }
  });
}

function arrayUnique(arr){
    let map={};
    
    return arr.filter(obj =>{
      let objID=obj.id;
      
      if(!map[objID]){
        map[objID]=true;
        return obj;
      }
    });
}

console.log("result",arrayUnion(a,b,c));

Solution 7:[7]

You can use flat and Set:

const union = (...arr) => [...new Set(arr.flat())];

console.log(union([1, 2], [2, 3], [3]));

Solution 8:[8]

It is really easy to do it in typescript using the set function.

const firstArr = [
    {
        id: '1',
        winner: 'Captain America',
    },
    {
        id: '4',
        winner: 'Aquaman',
    },
    {
        id: '2',
        winner: 'Captain America',
    },
    {
        id: '3',
        winner: 'Aquaman',
    },
]

const secondArr = [
    {
        id: '1',
        winner: 'Wonder women',
    },
    {
        id: '2',
        winner: 'Param',
        strenths: ['fly', 'fight', 'speed'],
    },
]
const mergedArray = [...secondArr, ...firstArr]

let set = new Set()
let unionArray = mergedArray.filter((item) => {
    if (!set.has(item.id)) {
        set.add(item.id)
        return true
    }
    return false
}, set)
 
console.log(unionArray);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Arnaud Valensi
Solution 2
Solution 3
Solution 4 John Salvatier
Solution 5 Murad Hossain
Solution 6
Solution 7 Ajeet Shah
Solution 8 DinoMyte