Informe de gastos multidivisa

Gana FxDart

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

Apple M1 Max, 32 GB de RAM · Dart 3.12.2 (compilado AOT) · 2026-08-24

N = 100

Tiempo Empate

Dart nativo 14 µs
FxDart 11 µs

Memoria pico Empate

Dart nativo 17.0 MB
FxDart 16.5 MB

N = 10,000

Tiempo Empate

Dart nativo 784 µs
FxDart 719 µs

Memoria pico Empate

Dart nativo 23.5 MB
FxDart 22.9 MB

N = 1,000,000

Tiempo Gana FxDart

Dart nativo 123.3 ms
FxDart 104.4 ms

Memoria pico Gana nativo

Dart nativo 201.8 MB
FxDart 220.0 MB

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í.