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

Monthly category report, sorted by spend

FxDart wins

Requirement

From a ledger that spills over from June into July 2026, build the July spending report: keep only July transactions, total each category, and print one line per category — biggest spend first. The data is in the code below; both versions must print the lines shown under Expected output.

Expected output
Food: $74.60
Bills: $60.34
Fun: $23.25
Transport: $14.15

Side by side

Native Dart

FxDart

Why they differ

Native Dart has no groupBy, so the loop does the grouping and the totalling at once inside a mutable map — compact, but the four requirements (July only, per category, totalled, ranked) are tangled into one body. The FxDart chain keeps them as four visible steps: filter the month, groupBy category, map each group to its total, sortBy descending — and join formats the report. Adding a requirement (say, a minimum total) is one more chain step; in the loop it is another branch inside an already-busy body.

Two FxDart spellings

The benchmark below carries a third bar, which only one other page does. The chain above is the one to write: filter and foldBy as two named steps, each answering one question. What it cannot do is inline its own predicate. filter is a lazy stage, so it keeps that predicate in an iterator field, and the AOT compiler cannot see through a field — every transaction pays a real indirect call whose body never fuses into the loop. foldBy does not have that problem; it is strict, so its callbacks are parameters and get inlined.

foldByOrSkip, shown above main in the FxDart panel, moves the test into the key: a null key skips the row, so one callback both selects and buckets, and it is a parameter of a body small enough to inline. Over 1,000,000 transactions that is the difference between the second and third bars; the first is the hand-written loop.

Write the chain by default — two unrelated questions read better as two steps. Reach for foldByOrSkip when the pipeline is hot and a profile says that predicate is the cost.

Benchmark

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

N = 100

Time Tie

Native Dart 2.3 µs
FxDart 6.2 µs
FxDart (strict) 6.0 µs

Peak memory Tie

Native Dart 16.5 MB
FxDart 16.3 MB
FxDart (strict) 16.5 MB

N = 10,000

Time Tie

Native Dart 106 µs
FxDart 139 µs
FxDart (strict) 119 µs

Peak memory FxDart wins

Native Dart 17.0 MB
FxDart 16.0 MB
FxDart (strict) 16.0 MB

N = 1,000,000

Time Native wins

Native Dart 11.3 ms
FxDart 14.5 ms
FxDart (strict) 12.6 ms

Peak memory Tie

Native Dart 120.4 MB
FxDart 120.0 MB
FxDart (strict) 119.8 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.