Informe de gastos multidivisa
Requisito
El libro de cuentas de un viaje (los datos están en el código) mezcla importes en EUR, GBP, JPY y USD. Convierte todo a USD con los tipos fijos del código y después informa de: los totales por categoría ordenados por gasto, las divisas que aparecen, el mayor gasto individual (con su importe original) y el total general. Ambas versiones deben imprimir el informe que aparece bajo Salida esperada.
Salida esperada
Trip expenses in USD (currencies: EUR, GBP, JPY, USD) Lodging $240.55 Travel $164.82 Food $37.85 Transit $22.50 Largest single expense: Travel $130.80 (120.00 EUR) Total: $465.72
Lado a lado
Dart nativo
FxDart
Por qué difieren
Normalizar primero —map de cada transacción a un par
(tx, usd)— permite que todas las preguntas posteriores
se resuelvan sobre una sola lista: foldBy +
sortBy para el desglose, uniq para la lista de
divisas, maxBy y sumBy para las líneas de
resumen. Cada línea del informe es un pipeline corto que da nombre a su
agregación. La versión nativa hace exactamente los mismos movimientos,
pero sin el vocabulario: los totales por categoría son un acumulador de
mapa hecho a mano, la ordenación necesita un comparador escrito a mano, el
máximo es un comparador de reduce y la lista de divisas
necesita el baile de toSet().toList()..sort(). Nada de esto
es difícil —simplemente hay más de todo, y menos de todo dice lo que
significa.
Que la agregación sea foldBy y no
groupBy + sumBy es deliberado, y merece un
momento. Aquí la respuesta es un número por categoría, así que
agrupar primero construiría una List con todas las
transacciones de cada categoría para luego plegarla y tirarla —asignación
proporcional a la entrada, para una respuesta proporcional al número de
categorías—. foldBy acumula directamente en el mapa de
resultado, que es exactamente lo que hace el bucle nativo de al lado. Sobre
un libro mayor de un millón de filas, esa única decisión vale unas 2,5× en
ambos lados; mira
Escribir pipelines rápidos.
Recurre a groupBy cuando de verdad quieras los miembros.
Benchmark
N = 100
Tiempo Empate
Memoria pico Empate
N = 10,000
Tiempo Empate
Memoria pico Empate
N = 1,000,000
Tiempo Gana FxDart
Memoria pico Gana nativo
Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.