Cálculo iterativo masivo: REDUCE + APILARV vs BISECCIÓN recursiva vs cálculo directo
Nuevo caso que combina logística portuaria con fórmulas avanzadas de Excel. Un miembro necesita calcular la distribución de días de almacenaje y tonelaje por buque en un puerto, procesando más de 26.000 filas de operaciones de carga (graneles sólidos, líquidos, carga general). Cada buque requiere cruzar datos de recaladas, fechas de llegada y maniobras, lo que genera dependencias entre filas.
El fichero adjunto contiene tres bloques paralelos de análisis (Granel Sólido, Granel Sólido Granos, Granel Sólido Harinas) con la misma lógica implementada de dos formas distintas para comparar rendimiento:
La solución intuitiva usa REDUCE + APILARV (iteración secuencial): REDUCE itera buque a buque y APILARV va apilando los resultados. Dentro de cada iteración se cruzan datos con BUSCARX, se filtran con FILTRAR y se agrupan con AGRUPARPOR. Funciona, pero es lenta porque cada paso acumula la matriz completa y realiza cálculos internos costosos.
El segundo enfoque usa una LAMBDA recursiva con bisección (divide and conquer). En lugar de procesar los buques uno a uno, parte la lista en dos mitades, procesa cada mitad por separado y combina con APILARV:
``
=LET(
...
F; LAMBDA(F; v;
LET(
n; FILAS(v);
SI(n = 1;
[procesar un solo buque];
APILARV(
F(F; TOMAR(v; n/2));
F(F; EXCLUIR(v; n/2))
)
)
)
);
F(F; lista_buques)
)
`
La bisección evita el problema de stack overflow que REDUCE sufre con muchas iteraciones, y el procesamiento "divide y vencerás" es más eficiente para matrices grandes.
John analiza el modelo a fondo y descubre un tercer enfoque: cálculo directo (sin iteración). Gran parte de los cálculos iterativos eran en realidad independientes entre buques: se podían resolver con AGRUPARPOR, BUSCARX y operaciones matriciales directas sin necesidad de iterar. Su versión reestructurada resulta ser la más rápida con diferencia.
La reflexión clave de Leo: "Siempre que se pueda, es mejor hacer cálculos directos que usar recursiones o iteraciones. El problema no era tanto la forma de iterar (REDUCE o bisección) sino todos los cálculos innecesarios dentro del bucle."
Como bonus, el fichero incluye un ajuste de distribución Gamma (GAMMA.DIST`) sobre los datos de permanencia, calculando media ponderada, varianza y parámetros alpha/beta para modelizar estadísticamente el comportamiento del almacenaje.
Un caso fascinante que mezcla logística real, funciones avanzadas y una lección de rendimiento: antes de optimizar el cómo se itera, merece la pena cuestionar si realmente necesitas iterar.
El problema: 26.000 filas de operaciones portuarias
Este caso mezcla logística portuaria real con fórmulas avanzadas. Un miembro de la comunidad necesita calcular la distribución de días de almacenaje y tonelaje por buque en un puerto, procesando más de 26.000 filas de operaciones de carga (graneles sólidos, líquidos y carga general). Cada buque obliga a cruzar recaladas, fechas de llegada y maniobras, lo que genera dependencias entre filas. El fichero implementa la misma lógica de dos formas distintas para comparar rendimiento, y de ahí sale una de las mejores lecciones de optimización que ha dado la comunidad.
Enfoque 1: REDUCE + APILARV (iteración secuencial)
La solución intuitiva usa REDUCE para iterar buque a buque y APILARV para ir apilando los resultados. Dentro de cada iteración se cruzan datos con BUSCARX, se filtran con FILTRAR y se agrupan con AGRUPARPOR:
`` =REDUCE(cabecera; lista_buques; LAMBDA(acumulado; buque; APILARV(acumulado; procesar(buque)) )) ``
Funciona, pero es lenta: en cada paso el acumulador arrastra la matriz completa calculada hasta ese momento, y encima repite cálculos internos costosos en cada vuelta.
Enfoque 2: LAMBDA recursiva con bisección
El segundo enfoque cambia la estrategia por un "divide y vencerás". En lugar de procesar los buques uno a uno, parte la lista en dos mitades, procesa cada mitad por separado y las combina con APILARV:
`` =LET( F; LAMBDA(F; v; LET( n; FILAS(v); SI(n = 1; procesar_un_buque(v); APILARV( F(F; TOMAR(v; n/2)); F(F; EXCLUIR(v; n/2)) ) ) ) ); F(F; lista_buques) ) ``
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. La bisección evita el desbordamiento de pila que sufre REDUCE con muchas iteraciones y suele ir más rápida en matrices grandes. La comunidad bautizó la técnica como el "Biseccionator".
Enfoque 3: cálculo directo (la gran lección)
John analiza el modelo a fondo y descubre algo revelador: buena parte de los cálculos no eran realmente iterativos. Muchos resultados eran independientes entre buques y se podían resolver con AGRUPARPOR, BUSCARX y operaciones matriciales directas, sin iterar en absoluto. Su versión reestructurada resulta ser, con diferencia, la más rápida.
La reflexión de Leo lo resume perfecto: lo importante no era tanto cómo iterar (REDUCE o bisección), sino todos los cálculos innecesarios que se metían dentro del bucle. Antes de optimizar el cómo iteras, pregúntate si de verdad necesitas iterar.
Bonus estadístico
El fichero incluye además un ajuste de distribución Gamma con GAMMA.DIST sobre los datos de permanencia, calculando media ponderada, varianza y los parámetros alpha y beta para modelizar el comportamiento del almacenaje. Un recordatorio de que Excel también sirve para modelado estadístico serio.
Funciones clave
REDUCE+APILARV: el patrón clásico de iteración acumulativa; cómodo pero costoso cuando el acumulador crece mucho.LAMBDArecursiva: permite implementar bisección llamando a la función sobre cada mitad del array.TOMARyEXCLUIR: parten el rango en dos para el "divide y vencerás".AGRUPARPORyBUSCARX: la base del cálculo directo, que resuelve sin iterar lo que parecía necesitar un bucle.GAMMA.DIST: modelado estadístico de la permanencia de la carga.
Conclusión
Tres formas de atacar el mismo modelo, y un orden de rendimiento claro: la iteración secuencial es la más lenta, la bisección la mejora, pero el cálculo directo las supera a todas porque elimina el trabajo innecesario en lugar de hacerlo más rápido. La moraleja va más allá de este caso: la mejor optimización no es acelerar el bucle, sino descubrir que no lo necesitabas. Casos así, con problemas reales y varias mentes buscándoles la vuelta, son el día a día de la comunidad de Influexcel.
Más contenido de Excel en InflueXcel
- Cuenta clientes y cervezas en Excel 🍺 Caso "La Taberna: El Poney Pisador" (Nivel 1) Tutorial🍺 Noche cerrada en Bree. Frodo, Sam, Merry y Pippin cruzan la puerta de El Poney Pisador huyendo de los Jinetes Negros: la sala está a reven
- SUMAR.SI.CONJUNTO en acción con El Señor de los Anillos 🃏 El 21 de La Comarca TutorialLo que practicamos en este caso: • Contar cartas por palo con CONTAR.SI • Sumar valores con condiciones (SUMAR.SI / SUMAR.SI.CONJUNTO) • Apl
- Reto de Excel: El cumpleaños de Bilbo 🎂 | CONTAR.SI y SUMAR.SI desde cero (Nivel 1) TutorialEn La Comarca se celebra el cumpleaños número 111 de Bilbo Bolsón: cerveza, pasteles, fuegos artificiales… y algún curioso escondido tras el
- ¡Excel PowerQuery Hack! Conexiones con rutas relativas en 10 minutos! Tutorial¿Harto de ajustar las conexiones en PowerQuery cada vez que compartes tu archivo de Excel? 🙄 Convierte las conexiones de PowerQuery con ruta
- Mejora un 90% el rendimiento de Power Query con SQLite TutorialPower Query es una herramienta potente para consolidar, combinar y calcular datos, pero cuando trabajamos con millones de registros y calcul
- Reorganizar tablas mensuales: cruzar por persona buscando en vertical y en horizontal CasoNuevo caso interesante de la comunidad. Juan tenía varias tablas mensuales (a veces más de una en el mismo mes) y quería reorganizarlas por
- Un dato de todas las hojas, escrito una sola vez CasoEsta semana surgió en la comunidad un reto muy habitual cuando un libro tiene muchas hojas: mostrar el valor de la celda B3 de cada hoja, in
- Un índice de hojas que se genera solo: HYPERLINK en rangos desbordados CasoEsta semana surgió en la comunidad un pequeño "expediente X". Un miembro llegó tras ver un vídeo con una idea clara en la cabeza: montar una
- Reformatear un código alfanumérico al teclear: de NN1234567 a NN-12345-67 CasoEsta semana surgió en la comunidad una duda muy práctica: cómo conseguir que al escribir un código tipo NN1234567 (dos letras seguidas de si
- Reclasificación contable: duplicar cada fila con una conversión distinta por columna, en un único bloque CasoInteresante reto contable planteado esta semana por un miembro de la comunidad. Juan parte de una tabla de apuntes contables (rango C7:P10)