Creating an array of cumulative sum in javascript

Viewed 49156

This is an example of what I need to do:

var myarray = [5, 10, 3, 2];

var result1 = myarray[0];
var result2 = myarray[1] + myarray[0];
var result3 = myarray[2] + myarray[1] + myarray[0];
var result4 = myarray[3] + myarray[2] + myarray[1] + myarray[0];

so all that would output 5, 15, 18, 20

but instead of writing out all the vars like that, I want it to say something like:

var result = arrayitem + the sum of any previous items 

Does that make sense? Is that possible? How do I do that?

24 Answers

An elegant solution copied from Nina Scholz, using currying to access the previous value.

const cumulativeSum = (sum => value => sum += value)(0);

console.log([5, 10, 3, 2].map(cumulativeSum));

cumulativeSum is the function value => sum += value, with sum initialized to zero. Every time it's called, sum is updated and will equal the previous value (output[n-1]) when called the next time (with input[n]).

Note that sum will need to be set to zero explicitly when you want to reuse the summation. The most convenient way to handle this may be to just inline the code instead of using a named function.

console.log([5, 10, 3, 2].map((sum => value => sum += value)(0)));
console.log([6, 10, 3, 2].map((sum => value => sum += value)(0)));

vs the unwanted behavior

const cumulativeSum = (sum => value => sum += value)(0);

console.log([5, 10, 3, 2].map(cumulativeSum));
console.log([6, 10, 3, 2].map(cumulativeSum));

Update 7.6.2022: You can use the comma operator instead of currying to make an easier-to-read version with explicit sum = 0.

console.log([5, 10, 3, 2].map((sum = 0, n => sum += n)));

Three years and no one thought to suggest this? :)

I needed to keep the results and just add a running total property. I had a json object with a date and revenue and wanted to display a running total as well.

//i'm calculating a running total of revenue, here's some sample data
let a = [
  {"date":  "\/Date(1604552400000)\/","revenue":  100000 },
  {"date":  "\/Date(1604203200000)\/","revenue":  200000 },
  {"date":  "\/Date(1604466000000)\/","revenue":  125000 },
  {"date":  "\/Date(1604293200000)\/","revenue":  400000 },
  {"date":  "\/Date(1604379600000)\/","revenue":  150000 }
];

//outside accumulator to hold the running total
let c = 0;

//new obj to hold results with running total
let b = a
  .map( x => ({...x,"rtotal":c+=x.revenue}) )
  
//show results, use console.table if in a browser console
console.log(b)

This question has been answered well by others but I'll leave my solution here too. I tried to be concise without sacrificing clarity.

myarray.reduce((a, e, i) => {
  // a: Accumulator; e: current Element; i: current Index
  return a.length > 0 ? [...a, e + a[i - 1]] : [e];
}, []);

Map, Filter, Reduce, Find, Some, etc. are highly underrated.

I came up with this ES6 one using array.map()

function prefixSum(nums) {
  let psum = 0;
  return nums.map(x => psum += x);
};

console.log(prefixSum([5, 10, 20, 30]));

Another clean one line solution with reduce and concat

var result = myarray.reduce(function(a,b,i){ return i === 0 ?  [b]: a.concat(a[i-1]+b);},0);
//[5, 10, 3, 2] => [5, 15, 18, 20]

A simple function using array-reduce.

const arr = [6, 3, -2, 4, -1, 0, -5];

const prefixSum = (arr) => {

  let result = [arr[0]]; // The first digit in the array don't change
  arr.reduce((accumulator, current) => {
       result.push(accumulator + current);

       return accumulator + current; // update accumulator
  });
  return result;
}

Old school and simpler :

let myarray = [5, 10, 3, 2], result = [];

for (let i = 0, s = myarray[0]; i < myarray.length; i++, s += myarray[i]) result.push(s);

console.log(result); // [5, 15, 18, 20]

Use arrow function instead of function, comma operator instead of return, and currentIndex in reduce callback.

[5, 10, 3, 2].reduce((r, a, i) => (r.push((i && r[i - 1] || 0) + a), r), []); // [ 5, 15, 18, 20 ]
/**
 * Turn an array of numbers to cumulative sum array
 * @param { Array } [1,2,3,4,5]
 * @return { Array } [1,3,6,10,15]
 */

const accumulate = (a, c) => a + c

const cusum = arr => arr.map((v, i, data) => {
    return data.slice(0, i + 1).reduce(accumulate)
})

/*Checkout the explanation below */

nums = [1,2,3,4]
var runningSum = function(nums) { 
shoppingCart =[];
runningtotal =0;  
nums.forEach(EachValue => {  
runningtotal += EachValue
shoppingCart.push(runningtotal);  
});
return shoppingCart       
};

console.log(runningSum(nums));

/* define some numbers*/

nums = [1,2,3,4]

/* assign function runningSum , some numbers*/

var runningSum = function(nums) { 
shoppingCart =[]; /* Create a empty shopping cart to store the items */
runningtotal =0;  /* Start with your beginning bill of zero items in the cart */

/* remove a number from list of numbers call each one of the numbers from the array => EachValue using a pointer function*/

nums.forEach(EachValue => {  

         (runningtotal += EachValue) 

/* Now add the value to the runningtotal to represent items prices*/

shoppingCart.push(runningtotal);  

/* Use the push method to place it into the new array called shopping cart */ });

return shoppingCart

/* output the items currently in the shopping cart with only 1d prices */

};

    nums = [1,2,3,4]
    var runningSum = function(nums) { 
    shoppingCart =[];
    runningtotal =0;  
    nums.forEach(EachValue => {  
    runningtotal += EachValue
    shoppingCart.push(runningtotal);  
    });
    return shoppingCart       
    };

    console.log(runningSum(nums));

var nums= [5, 10, 3, 2];
var runningSum = function(nums) {
   
    nums.reduce((acc, _, i) => (nums[i] += acc));
    return nums;
};

Here's a simple answer using recursion.

function sumArrayRec(arr) {
  return sumArrayHelper(0, 0, [], arr)
}

function sumArrayHelper(prevSum, index, sums, arr) {
  if (!arr.length) {
    return sums
  }

  let curSum = arr[index] + prevSum
  sums.push(curSum)
  array.shift()

  return sumArrayHelper(curSum, index++, sums, array)
}

Here is the simplest answer using a reducer.

let runningSum = function(nums) {
    nums.reduce((pre, curr, i) => {
        nums[i] = pre + curr;
        return nums[i];
    }, 0);
    return nums;
};

console.log(runningSum([1,2,3,5,6,8]));

Runtime: 133 ms, faster than 5.02% of JavaScript online submissions for Running Sum of 1d Array. Memory Usage: 41.9 MB, less than 93.93% of JavaScript online submissions for Running Sum of 1d Array.

Related