Эта страница ещё не переведена, поэтому показана на английском. Помогите с переводом

Multi-currency expense report

FxDart wins

Requirement

A trip ledger (data in the code) mixes EUR, GBP, JPY, and USD amounts. Convert everything to USD with the fixed rates in the code, then report: per-category totals sorted by spend, the currencies seen, the largest single expense (with its original amount), and the grand total. Both versions must print the report under Expected output.

Expected output
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

Side by side

Native Dart

FxDart

Why they differ

Normalizing first — map each transaction to a (tx, usd) pair — lets every later question run over one list: foldBy + sortBy for the breakdown, uniq for the currency list, maxBy and sumBy for the summary lines. Each report line is one short pipeline that names its aggregation. The native version makes the identical moves but without the vocabulary: the per-category totals are a hand-rolled map accumulator, the sort needs a comparator spelled out, the maximum is a reduce comparator, and the currency list needs the toSet().toList()..sort() shuffle. Nothing is hard — there is just more of it, and less of it says what it means.

The aggregation is foldBy rather than groupBy + sumBy on purpose, and it is worth a moment. The answer here is one number per category, so grouping first would build a List of every transaction under each category and then immediately fold it away — allocation proportional to the input, for an answer proportional to the number of categories. foldBy accumulates straight into the result map, which is exactly what the native loop beside it does. On a million-row ledger that single choice is worth roughly 2.5× on both sides; see Writing fast pipelines. Reach for groupBy when you actually want the members.

Benchmark

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

N = 100

Time Tie

Native Dart 14 µs
FxDart 11 µs

Peak memory Tie

Native Dart 17.0 MB
FxDart 16.5 MB

N = 10,000

Time Tie

Native Dart 784 µs
FxDart 719 µs

Peak memory Tie

Native Dart 23.5 MB
FxDart 22.9 MB

N = 1,000,000

Time FxDart wins

Native Dart 123.3 ms
FxDart 104.4 ms

Peak memory Native wins

Native Dart 201.8 MB
FxDart 220.0 MB

Bars are medians of repeated timed iterations in fresh processes per side (small N is batched for timer resolution). Sides within 5% of each other — or within 0.6 ms, a difference no person can perceive — count as a tie; close relative races are re-measured up to 5 runs. In an app, anything under a few milliseconds is invisible to the user regardless of which bar is shorter. Memory is peak process RSS. The Dart VM and the dataset are identical on both sides, so the difference between the two bars is what the pipeline itself holds onto.