Skip to content

Instantly share code, notes, and snippets.

@hunan-rostomyan
Created July 20, 2016 03:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hunan-rostomyan/0386d252b5206e84bb3e70df71d7fcce to your computer and use it in GitHub Desktop.
Save hunan-rostomyan/0386d252b5206e84bb3e70df71d7fcce to your computer and use it in GitHub Desktop.
Scan (prefix sum, cumulative sum, inclusive scan) in JavaScript
// What does scan*(id, op, arr) do?
//
// Given an identity element `id`, a binary associative
// operator `op`, and a list `arr`, returns a list of the
// same size where each item in that list is the op-sum
// of all previous items.
//
// E.g. sum(0, +, [3, 4]) => [(0 + 3), (3 + 4)]
// E.g. sum(1, *, [2, 5]) => [(1 * 2), (2 * 5)]
// Helpers
function cons(x, lst) {return lst.concat([x]);}
function first(list) {return list[0];}
function last(list) {return list.slice(-1)[0];}
function rest(list) {return list.slice(1);}
function add(a, b) {return a + b;}
function mult(a, b) {return a * b;}
// Variant 1 (Imperative)
function scanImperative(id, op, arr) {
var ret = [], i;
for (i = 0; i < arr.length; i++) {
ret = cons(op(arr[i], (last(ret) || id)), ret);
}
return ret;
}
// Variant 2 (Recursive)
function scanRecursive(id, op, arr) {
function helper(toRet, arr) {
if (!arr.length) {return toRet;}
var prev = (last(toRet) || id);
return helper(cons(op(first(arr), prev), toRet), rest(arr));
}
return helper([], arr);
}
// Variant 3 (Functional)
function scanFunctional(id, op, arr) {
return arr.reduce(function(prev, cur) {
return cons(op(cur, (last(prev) || id)), prev);
}, []);
}
// Usage
var scan = scanFunctional; // choose your favorite version
scan(0, add, [2, 3, 4]); //=> [(0 + 2), (2 + 3), (5 + 4)] = [2, 5, 9]
scan(1, mult, [2, 3, 4]); //=> [(1 * 2), (2 * 3), (6 * 4)] = [2, 6, 24]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment