summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2026-04-09 16:54:31 -0300
committerEuAndreh <eu@euandre.org>2026-04-09 16:54:31 -0300
commit4f53f8998cbed82b0c04432b305c4a37caddd8e6 (patch)
tree9f4d758a0c6acffe19a2f608688d8136f9f337a0
parentMakefile: Align ending backslack (diff)
downloadsjs-4f53f8998cbed82b0c04432b305c4a37caddd8e6.tar.gz
sjs-4f53f8998cbed82b0c04432b305c4a37caddd8e6.tar.xz
src/sjs.mjs: Loop for reduce to avoid stack overflowsHEADmain
-rw-r--r--src/sjs.mjs22
-rw-r--r--tests/sjs.mjs46
2 files changed, 9 insertions, 59 deletions
diff --git a/src/sjs.mjs b/src/sjs.mjs
index aae85a7..aafd7ba 100644
--- a/src/sjs.mjs
+++ b/src/sjs.mjs
@@ -292,20 +292,16 @@ export const isReduced = x => x instanceof Reduced;
export const reduced = x => new Reduced(x);
-const reduceRec = (coll, fn, acc, index) =>
- isReduced(acc) ? acc.value :
- index === coll.length ? acc :
- reduceRec(
- coll,
- fn,
- fn(acc, coll[index], index, coll),
- index + 1,
- );
+export const reduce = (coll, fn, init) => {
+ let acc = init === undefined ? coll[0] : init;
+ let start = init === undefined ? 1 : 0;
+ for (let i = start; i < coll.length; i++) {
+ acc = fn(acc, coll[i], i, coll);
+ if (isReduced(acc)) return acc.value;
+ }
+ return acc;
+};
-export const reduce = (coll, fn, init) =>
- init === undefined
- ? reduceRec(coll.slice(1), fn, coll[0], 0)
- : reduceRec(coll, fn, init, 0);
const reductionsRec = (coll, fn, acc, index, steps) => {
if (isReduced(acc)) {
diff --git a/tests/sjs.mjs b/tests/sjs.mjs
index 9376429..01871ae 100644
--- a/tests/sjs.mjs
+++ b/tests/sjs.mjs
@@ -30,7 +30,6 @@ import {
makeRandom,
isReduced,
reduced,
- reduceRec,
reduce,
reductionsRec,
reductions,
@@ -897,50 +896,6 @@ const test_reduced = t => {
});
};
-const test_reduceRec = t => {
- t.start("reduceRec()");
-
- t.testing("return the value if isReduced()", () => {
- t.assertEq(reduceRec(null, null, reduced("abc"), null), "abc");
- });
-
- t.testing("the bare value if at the end of the collection", () => {
- t.assertEq(reduceRec([], null, "acc", 0), "acc");
- t.assertEq(reduceRec([1, 2], null, "acc", 2), "acc");
- });
-
- t.testing("recurse while applying function", () => {
- const expected = [{
- acc: -5,
- el: 4,
- index: 3,
- coll: [1, 2, 3, 4, 5],
- ret: -1,
- }, {
- acc: -1,
- el: 5,
- index: 4,
- coll: [1, 2, 3, 4, 5],
- ret: 4,
- }];
- const calls = [];
- const fn = (acc, el, index, coll) => {
- const ret = acc + el;
- calls.push({
- acc,
- el,
- index,
- coll,
- ret,
- });
- return ret;
- };
- const coll = [1, 2, 3, 4, 5];
- t.assertEq(reduceRec(coll, fn, -5, 3), 4);
- t.assertEq(calls, expected);
- });
-};
-
const test_reduce = t => {
t.start("reduce()");
@@ -1087,7 +1042,6 @@ runTests([
test_makeRandom,
test_isReduced,
test_reduced,
- test_reduceRec,
test_reduce,
test_reductionsRec,
test_reductions,