Ston Jarks
Ston Jarks

Reputation: 53

Merge multiple arrays of objects by common object key

I have a problem and I hope you kind JavaScript people on Stack Overflow can help me out with this.

Given the following arrays:

var array1 = [{address: "www.example.com", hits: 1}, {address: "www.anotherone.org", hits: 10}]
var array2 = [{address: "www.example.com", buttons: 1}, {address: "www.yetanotherone.info", buttons: 2}]
var array3 = [{address: "www.example.com", cons: 1}, {address: "andevenonemore.com", cons: 1}]

I want to merge these array by the address key, that will be common in all arrays but may differ in value. If a address value is not in an array, it should default to 0. So, the result array should look like this:

var resultArray = [{
  address: "www.example.com",
  hits: 1,
  buttons: 1,
  cons: 1
}, {
  address: "www.anotherone.org",
  hits: 1,
  buttons: 0,
  cons: 0
}, {
  address: "www.yetanotherone.info",
  hits: 0,
  buttons: 2,
  cons: 0
}, {
  address: "andevenonemore.com",
  hits: 0,
  buttons: 0,
  cons: 1
}]

The merge will happen on the server, and I have the possibility to use Underscore.js.

I really hope, somebody much smarter than me can give me an efficient way to solve this. Really appreciate your help!

Upvotes: 1

Views: 140

Answers (2)

Gruff Bunny
Gruff Bunny

Reputation: 27976

I know that there is already an accepted answer but here's one that uses underscore. It first groups by address and then extends the starting object with each object in the group.

var data = [].concat(array1, array2, array3);

var extendArray = function(arr){
   return _.reduce(arr, (memo,val) => _.extend(memo, val), {hits: 0, buttons: 0, cons: 0});
}

var resultArray = _.chain(data)
   .groupBy('address')
   .map(extendArray)
   .value()

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386600

In plain Javascript you could use a hash table for the reference to a single address item and count the values you need.

var array1 = [{ address: "www.example.com", hits: 1 }, { address: "www.anotherone.org", hits: 10 }],
    array2 = [{ address: "www.example.com", buttons: 1 }, { address: "www.yetanotherone.info", buttons: 2 }],
    array3 = [{ address: "www.example.com", cons: 1 }, { address: "andevenonemore.com", cons: 1 }],
    grouped = [];

[].concat(array1, array2, array3).forEach(function (a) {
    if (!this[a.address]) {
        this[a.address] = { address: a.address, hits: 0, buttons: 0, cons: 0 };
        grouped.push(this[a.address]);
    }
    Object.keys(a).forEach(function (k) {
        if (k !== 'address') {
            this[a.address][k] += a[k];
        }
    }, this);

}, Object.create(null));

console.log(grouped);

Upvotes: 1

Related Questions