1

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!

1
  • 1
    I feel like I just left this party. Commented Jul 19, 2016 at 7:37

2 Answers 2

1

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);

Sign up to request clarification or add additional context in comments.

Comments

1

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()

2 Comments

Gruff, nevermind! Thanks a lot, it's always good to have alternatives. Do you know how Underscore compares to plain solution in terms of performance?
Underscore is written in js and bespoke javascript which is tailored to the solution will generally be quicker. However a solution in underscore is generally more expressive of what you're trying to achieve and backed by a ton of tests.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.