Multi dimensional array cumulative sum in Javascript - Stack Overflow

Given a multi-dimensional array:var a = [[3,2,5], [4,1,7], [1,6,8]];I would like to do a cumulative sum

Given a multi-dimensional array:

var a = [[3,2,5], [4,1,7], [1,6,8]];

I would like to do a cumulative sum of each array to return the following result:

[[3,2,5], [7,3,12], [8,9,20]];
  • cum sum on 1st elements of each sub-array: 3 4 1
  • cum sum on 2nd elements of each sub-array: 2 1 6
  • cum sum on 3rd elements of each sub-array: 5 7 8

I've tried using reduce(), but can't quite get the expected result.

Any suggestions, much appreciated.

S

UPDATE - Taking it to the next level:

var a = [
    [new Date(), 3,2,5], 
    [new Date(), null,1,7], 
    [new Date(), null,6,8], 
    [new Date(), 1,2,3]
];

Should result in:

[[new Date(), 3,2,5], 
 [new Date(), null,3,12],
 [new Date(), null,9,20],
 [new Date(), 4,11,23]]

My approach was to create a multi-dimensional offsetIndex array:

var offsetIdx = [];
        for (var i=1; i<a.length; i++) {

            for (var z=0; z<a[i].length; z++) {
                var zValue = a[i][z];

                oIdx = offsetIdx[z] || 0;

                a[i][z] = zValue && z!==0 ? a[i-1-oIdx][z] + zValue : zValue;

                if(!zValue){
                    offsetIdx[z] = oIdx + 1;
                } else {
                    offsetIdx[z] = 0; 
                }
            }
        }

Happy to see other approaches and ways of making it ultra light-weight.

Given a multi-dimensional array:

var a = [[3,2,5], [4,1,7], [1,6,8]];

I would like to do a cumulative sum of each array to return the following result:

[[3,2,5], [7,3,12], [8,9,20]];
  • cum sum on 1st elements of each sub-array: 3 4 1
  • cum sum on 2nd elements of each sub-array: 2 1 6
  • cum sum on 3rd elements of each sub-array: 5 7 8

I've tried using reduce(), but can't quite get the expected result.

Any suggestions, much appreciated.

S

UPDATE - Taking it to the next level:

var a = [
    [new Date(), 3,2,5], 
    [new Date(), null,1,7], 
    [new Date(), null,6,8], 
    [new Date(), 1,2,3]
];

Should result in:

[[new Date(), 3,2,5], 
 [new Date(), null,3,12],
 [new Date(), null,9,20],
 [new Date(), 4,11,23]]

My approach was to create a multi-dimensional offsetIndex array:

var offsetIdx = [];
        for (var i=1; i<a.length; i++) {

            for (var z=0; z<a[i].length; z++) {
                var zValue = a[i][z];

                oIdx = offsetIdx[z] || 0;

                a[i][z] = zValue && z!==0 ? a[i-1-oIdx][z] + zValue : zValue;

                if(!zValue){
                    offsetIdx[z] = oIdx + 1;
                } else {
                    offsetIdx[z] = 0; 
                }
            }
        }

Happy to see other approaches and ways of making it ultra light-weight.

Share Improve this question edited Mar 29, 2016 at 8:25 Seb asked Mar 24, 2016 at 2:42 SebSeb 891 silver badge8 bronze badges 4
  • How is it that your output array can have the same number of elements, given that a sum will be applied to the input? – New Alexandria Commented Mar 24, 2016 at 2:47
  • @NewAlexandria: He's accumulating the result as he goes along into each array, so the first array doesn't change, the second is the sum of the first plus itself (for each member respectively), the third is the sum of the result of the second, again plus its own respective members, and so on. – user1106925 Commented Mar 24, 2016 at 2:50
  • Correct. I leaned towards the reduce() function as it passes a reference to the previous element. I've seen examples with flat 1 dim arrays, but can't quite adapt it to acmodate a multi-dim array. – Seb Commented Mar 24, 2016 at 2:54
  • It would help if you post your reduce() code. It should work and I'd like to see what you're doing wrong (or I'm doing wrong) if it's not. – djechlin Commented Mar 24, 2016 at 3:10
Add a ment  | 

5 Answers 5

Reset to default 3
for (var i=1; i<a.length; i++) {
  for (var z=0; z<a[i].length; z++) {
   a[i][z] = a[i-1]][z] + a[i][z]
  }
}

The array should be updated dynamically as the loop runs on. This is destructive so it will modify the original array.

  function cumulativeSum(arr) {
    var result = [arr[0]];
    for(var i = 1; i < arr.length; i++) {
        result.push([]);
        for(var j = 0; j < arr[0].length; j++) {
          result[i].push(result[i - 1][j] + arr[i][j]);
        }
    }
    return result;
}
    
document.body.innerHTML = JSON.stringify(cumulativeSum(
  [[3,2,5], [4,1,7], [1,6,8]]
))

Unlike the other answer, this one is not destructive, preserving the original array and returning the result.

Using Array.reduce, it would look like this

var arr  = [[3,2,5], [4,1,7], [1,6,8]];

var arr2 = arr.reduce(function(a,b) {
    var nested = Array.isArray(a[0]);
    b = b.map(function(x,i) {
    	return x + (nested ? a[a.length-1] : a)[i];
    });
    if ( nested ) a.push(b);
    return nested ? a : [a,b];
});

document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';

Here's a sligthly "optimized" (golfed) version, passing in a starting point for the reduction and slicing the array

var arr  = [[3,2,5], [4,1,7], [1,6,8]];

var arr2 = arr.slice(1).reduce(function(a,b) {
	return [a.push(b.map(function(x,i) {return x+a[a.length-1][i]})), a].pop();
},[arr[0]]);

document.body.innerHTML = '<pre>' + JSON.stringify(arr2, 0, 4) + '</pre>';

Making it a one-liner by using ES2015

var arr  = [[3,2,5], [4,1,7], [1,6,8]];
var a2 = arr.slice(1).reduce((a,b)=>[a,a.push(b.map((x,i)=>x+a[a.length-1][i]))][0],[arr[0]]);

document.body.innerHTML = '<pre>' + JSON.stringify(a2, 0, 4) + '</pre>';

This will give you the sum across all elements. Not quite what you ask, but I will leave this answer here for future visitors who catch the question title.

  1. Flatten first using your favorite library (underscore and lodash both have it)
  2. Then reduce + sum .

    _.flatten([1, [2, [3, [4]], 5]]);
    // → [1, 2, [3, [4]], 5]
    

What a mathy question.

Why not transpose the array first? An answer on this question - Transposing a 2D-array in JavaScript - suggests the underscore.js solution:

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])

to do this. There are many ways.

Then the sum should be much easier - just .map(f) where f is your sum on one array function.

IMO this is a good and readable solution, because "transpose+sum" is very true to the column-sum nature of the question, and I would avoid an imperative or loop-heavy solution that obscures this.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744683153a4587755.html

相关推荐

  • Multi dimensional array cumulative sum in Javascript - Stack Overflow

    Given a multi-dimensional array:var a = [[3,2,5], [4,1,7], [1,6,8]];I would like to do a cumulative sum

    1天前
    30

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信