0

I have a project that requires me to add the values of multiple arrays, not necessarily all the same length.

I have 8 arrays that can be of varying lenght:

p1 = [1,5,6,8,3,8,]
p2 = [3,3,3,2,8,3,3,4]
p3 = [1,2,3,4,5,6,7,8,9]
p4 = [1,3,4,5,6,7,2,0,2,8,7]

and so on.

What I need to do is add the same key values together to make 1 'results' array, that would look something like:

results = [6, 13, 16, 19, 22, 24, 12, 12, 11, 8, 7]

I've found some code on Stackoverflow that does the job beautifully in most browsers, with the exception of IE8.

Javascript merge 2 arrays and sum same key values

Here is the code that works in most browsers:

    var sums = {}; // will keep a map of number => sum
    [p1, p2, p3, p4, p5, p6, p7, p8].forEach(function(array) {
    //for each pair in that array
    array.forEach(function(pair) {
                    // increase the appropriate sum
                    sums[pair[0]] = pair[1] + (sums[pair[0]] || 0);
            });
    });



    // now transform the object sums back into an array of pairs, and put into array named 'results'...
    var results = [];
    for(var key in sums) {
            results.push([key, sums[key]]);
    }

The problem (I think) is that IE8 doesn't support forEach. Is there a way to do this without using forEach, either with plain Javascript or jQuery?

3 Answers 3

0

Rather than changing your code, you could shim forEach.

Here is the code from MDN, which is pretty much the "official" version:

if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisArg */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        fun.call(thisArg, t[i], i, t);
    }
  };
}

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Obviously, instead of using forEach you can use a regular for, but that would mean changing rather elegant code just for the sake of a bad apple.

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

5 Comments

Thanks for the answer Tibos, but as a javascript/jquery novice I'm a little lost as to how you actually use the shim? Any chance you can explain?
Just place it before any of the calls to forEach are made. The code basically checks if forEach has been defined and if it hasn't adds an implementation. From that point on you can use forEach knowing that either the native implementation exists or the shim does.
Had to redeem myself. jsperf.com/adding-up-by-key-values. I updated the JSFiddle to try and match what you had too. jsfiddle.net/rSMxX/2
@Mark yes, from a performance stand point, a lot more operations are done in the forEach that for this particular usage are not needed, so it is slower. It is impressive just how much slower it is, but still. I favor the functional methods of iterating over arrays because the extra code clarity is usually worth more than the performance boost if it is not the bottleneck. If it turns out that a forEach is a bottleneck, i will optimize it, but not before.
Yeah I don't think I got the [p1,p2,p3...].foreach to work right on jsfiddle. I'm getting a NaN. Updated jsfiddle. jsfiddle.net/rSMxX/3
0

the jquery version is:

$.each(array,function(i,pair){ 
    ....
});

and the pure js:

for (var i =0;i<array.length;i++){
  var pair = array[i];
  ....
}

or to make the original work:

if (!Array.prototype.forEach){
  Array.prototype.forEach = function(f){
    for (int i=0;i<this.length;i++){
      f(this[i]);
    }
  }
}

Array.prototype.forEach polyfill

Comments

0

I just cut straight to your result you wanted. But from a performance standpoint I'd do some jsperf.com testing on some of the loops and benching how the browsers crunch the numbers and get a feel for $.each vs for vs while loops and prototypes.

function sumTotals(arr) {
    var sum = 0,
        len = arr.length,
        i = 0;
    while (i < len) {
        sum += arr[i] || 0;
        i += 1;
    }
    return sum;
}
while (i < len ) {
    sums.push(sumTotals(merged[i]));
    i += 1;
}
alert(sums);

http://jsfiddle.net/rSMxX/

Updated my quick answer to try and match what you showed. But based on what I'm using for your p1-8 arrays the code you have there with it wasn't flying. I'm getting TypeError 'undefined' is not an object (evaluating forEach). So apples to apples, would probably have to fix that.

while (i < len ) {
    var j = 0,
        mlen = merged[i].length;
    while (j < mlen) {        
        sums[j] = (merged[i][j] || 0) + (sums[j] || 0);
        j += 1;
    }
    i += 1;
}
for(var key in sums) {
    //results.push([key, sums[key]]);
    results.push(sums[key]);
}
alert(results);

http://jsperf.com/adding-up-by-key-values and http://jsfiddle.net/rSMxX/2/

2 Comments

Thanks Mark. I've checked this out and it appears to sum the keys for each individual array and put it into an array. I need it to sum the keys for each of the 8 arrays respectively (p1[0] + p2[0] + p3[0] etc..) and put the results into an array. Sorry if I didn't explain this well enough.
My bad, you said add the keys values together and I blew by and added the sum of the array.

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.