locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
47 lines (46 loc) • 1.75 kB
JavaScript
function isScanReducer(value) {
return typeof value === 'function';
}
export function scan(values, initialOrReducer, maybeReducer) {
// discuss at: https://locutus.io/elixir/scan/
// parity verified: Elixir 1.18
// original by: Kevin van Zonneveld (https://kvz.io)
// note 1: Produces running accumulator states, similar to Elixir Enum.scan/2 and Enum.scan/3.
// example 1: scan([1, 2, 3, 4], (acc, value) => Number(acc) + Number(value))
// returns 1: [1, 3, 6, 10]
// example 2: scan([1, 2, 3], 10, (acc, value) => Number(acc) + Number(value))
// returns 2: [11, 13, 16]
// example 3: scan([], 5, (acc, value) => Number(acc) + Number(value))
// returns 3: []
if (!Array.isArray(values)) {
return [];
}
const hasInitial = typeof maybeReducer === 'function';
if (values.length === 0) {
return [];
}
const out = [];
if (hasInitial) {
const reducer = maybeReducer;
if (!isScanReducer(reducer)) {
throw new TypeError('scan(): reducer must be a function');
}
let accumulator = initialOrReducer;
for (let i = 0; i < values.length; i++) {
accumulator = reducer(accumulator, values[i], i, values);
out.push(accumulator);
}
return out;
}
if (!isScanReducer(initialOrReducer)) {
throw new TypeError('scan(): reducer must be a function');
}
const reducer = initialOrReducer;
let accumulator = values[0];
out.push(accumulator);
for (let i = 1; i < values.length; i++) {
accumulator = reducer(accumulator, values[i], i, values);
out.push(accumulator);
}
return out;
}