Full monthly ledger report
Requirement
From one month of ledger transactions (data in the code), build a single report string with three sections: the total spent (income excluded), a per-category breakdown sorted by spend, and the top 3 merchants as a numbered list. Both versions must print exactly the report shown under Expected output.
Expected output
July 2026 ledger Total spent: $201.99 By category: Bills $88.44 Food $84.40 Fun $15.00 Transport $14.15 Top merchants: 1. Electric Co $60.34 2. Green Grocer $43.20 3. Water Works $28.10
Side by side
Native Dart
FxDart
Why they differ
Each report section is the same shape in FxDart: groupBy →
sumBy per group → sortBy descending — then
take and zipWithIndex turn the merchant section
into a numbered top-3 without an index variable. The native version has
to say each of those steps in a different dialect: fold with
a seed for every sum, sortedBy<num> with a negated
key, a collection-for for one section and an indexed for
loop for the other. The report grows section by section on both sides —
but only one side grows by appending pipeline steps rather than
accumulating differently-shaped intermediate variables.
Benchmark
N = 100
Time Tie
Peak memory Tie
N = 10,000
Time Tie
Peak memory FxDart wins
N = 1,000,000
Time FxDart wins
Peak memory FxDart wins
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.