Optimización de REDUCE+APILARV con LAMBDA recursiva en bisección

Alejandro plantea un reto de rendimiento interesante: tiene una fórmula LET enorme que calcula la permanencia de carga en puerto por matrícula, teniendo en cuenta los retiros parciales. La fórmula funciona correctamente, pero tarda entre 1 y 5 minutos en procesar los datos completos. El corazón de la fórmula es un REDUCE que acumula filas con APILARV en cada iteración:

``
x;REDUCE(
{"Matr";"Fecha";"Días";"Saldo";"Retiro"};
_matralm;
LAMBDA(a;v;APILARV(a;LET(
...cálculos por matrícula...
APH(a;b;c;TOM(d;;-1))
)))
)
`

La fórmula original usa AGRUPARPOR, BUSCARX, ELEGIRCOLS, EXPANDIR, EXCLUIR, FILTRAR y varias funciones más dentro de cada paso del REDUCE, con alias de funciones para acortar la expresión (FIL para FILTRAR, ELE para ELEGIRCOLS, etc.).

Leo identifica inmediatamente el cuello de botella: el acumulador del REDUCE crece con cada paso, y en cada iteración tiene que trabajar con todos los datos acumulados hasta ese momento. Esto hace que el rendimiento se degrade exponencialmente con el número de matrículas.

La solución que propone Leo es sustituir el REDUCE + APILARV por una LAMBDA recursiva con bisección. En lugar de acumular fila a fila (complejidad O(n²)), la técnica divide el array por la mitad en cada paso y combina los resultados recursivamente (complejidad O(n·log n)):

`
F;LAMBDA(F;v;LET(
n;FILAS(v);
SI(n=1;
LET(
...mismo cálculo por matrícula individual...
APH(a;b;c;TOM(d;;-1))
);
APILARV(
F(F;TOMAR(v;n/2));
F(F;EXCLUIR(v;n/2))
)
)
));x;APILARV(
{"Matr";"Fecha";"Días";"Saldo";"Retiro"};
F(F;_matralm)
)
`

El patrón clave es F(F;TOMAR(v;n/2)) y F(F;EXCLUIR(v;n/2)): la LAMBDA se llama a sí misma con cada mitad del array. Cuando queda un solo elemento (n=1), ejecuta el cálculo real. Los resultados parciales se van apilando con APILARV al subir por la recursión.

Leo entrega la fórmula optimizada aproximadamente una hora después, trabajando "a ciegas" sin tener acceso al fichero original. La comunidad bautiza la técnica como "Biseccionator".

Esta técnica de bisección es aplicable a cualquier fórmula donde REDUCE + APILARV` se use para construir un resultado fila a fila, y la mejora de rendimiento es tanto más notable cuanto mayor sea el conjunto de datos.

Más contenido de Excel en InflueXcel