From 0353ae7bf69d0eabadef645462134c8bb9dca3d6 Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 12 Aug 2026 20:06:25 +0300 Subject: [PATCH] extract filterSameDimension/reduceCompatible in AGG_FUNCS chart/min/max repeated the same same-dimension filter, and sum/avg repeated the same left-to-right accumulation loop. --- src/engine/evaluator.ts | 59 ++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/engine/evaluator.ts b/src/engine/evaluator.ts index 8a7933d..02de873 100644 --- a/src/engine/evaluator.ts +++ b/src/engine/evaluator.ts @@ -414,11 +414,31 @@ function evalGoalSeek(lhsNode: Node, rhsNode: Node, ctx: EvalCtx): Value { return qty(lo.plus(hi).div(2)); } +/** Lines whose unit shares the first line's dimension (mixed-dimension blocks skip the rest). */ +function filterSameDimension(block: Quantity[]): Quantity[] { + const refDim = block[0].unit?.dimension ?? null; + return block.filter((q) => (q.unit?.dimension ?? null) === refDim); +} + +/** Adds compatible lines left to right, silently skipping ones with an incompatible dimension. */ +function reduceCompatible(block: Quantity[]): { acc: Quantity; counted: number } { + let acc = block[0]; + let counted = 1; + for (let i = 1; i < block.length; i++) { + try { + acc = numericAdd(acc, block[i], 1); + counted++; + } catch { + // skip lines with incompatible dimensions + } + } + return { acc, counted }; +} + const AGG_FUNCS: Record Value> = { count: (block) => qty(new Decimal(block.length)), chart: (block) => { - const refDim = block[0].unit?.dimension ?? null; - const compatible = block.filter((q) => (q.unit?.dimension ?? null) === refDim); + const compatible = filterSameDimension(block); if (compatible.length < 2) throw new EvalError("need at least 2 values for chart"); return { kind: "chart", @@ -426,39 +446,12 @@ const AGG_FUNCS: Record Value> = { unitLabel: block[0].unit?.format ?? null, }; }, - min: (block) => { - const refDim = block[0].unit?.dimension ?? null; - const compatible = block.filter((q) => (q.unit?.dimension ?? null) === refDim); - return compatible.reduce((best, q) => toBase(q).lt(toBase(best)) ? q : best); - }, - max: (block) => { - const refDim = block[0].unit?.dimension ?? null; - const compatible = block.filter((q) => (q.unit?.dimension ?? null) === refDim); - return compatible.reduce((best, q) => toBase(q).gt(toBase(best)) ? q : best); - }, + min: (block) => filterSameDimension(block).reduce((best, q) => toBase(q).lt(toBase(best)) ? q : best), + max: (block) => filterSameDimension(block).reduce((best, q) => toBase(q).gt(toBase(best)) ? q : best), product: (block) => qty(block.reduce((acc, q) => acc.mul(q.value), new Decimal(1))), - sum: (block) => { - let acc = block[0]; - for (let i = 1; i < block.length; i++) { - try { - acc = numericAdd(acc, block[i], 1); - } catch { - // skip lines with incompatible dimensions - } - } - return acc; - }, + sum: (block) => reduceCompatible(block).acc, avg: (block) => { - let acc = block[0]; - let counted = 1; - for (let i = 1; i < block.length; i++) { - try { - acc = numericAdd(acc, block[i], 1); - counted++; - } catch { - // skip lines with incompatible dimensions - } - } + const { acc, counted } = reduceCompatible(block); return qty(acc.value.div(counted), acc.unit); } };