Esta página ainda não foi traduzida, por isso é exibida em inglês. Ajude a traduzir

Cohort retention table

FxDart wins

Requirement

Each user (data in the code) has a signup month and the list of months they were active. Group users into cohorts by signup month and, for every later month, print what percentage of the cohort was still active — one row per cohort, oldest first. Both versions must print the table shown under Expected output.

Expected output
Cohort retention by signup month
2026-04 (4 users): 2026-05 50% | 2026-06 50% | 2026-07 25%
2026-05 (3 users): 2026-06 33% | 2026-07 67%
2026-06 (2 users): 2026-07 50%

Side by side

Native Dart

FxDart

Why they differ

A retention table is a pipeline inside a pipeline: cohorts on the outside, months on the inside. In FxDart both layers are expressions — groupBysortBymap over cohorts, and inside each row dropWhile skips months up to the signup month before filter + size count the still-active users. The native version needs a mutable accumulator list per layer (rows, cells) and two nested for loops to stitch them together; the actual retention logic is the same, but it is spread across loop bodies instead of being the visible spine of the code.

Benchmark

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

N = 100

Time Tie

Native Dart 47 µs
FxDart 37 µs

Peak memory Tie

Native Dart 16.5 MB
FxDart 17.1 MB

N = 10,000

Time Tie

Native Dart 2.43 ms
FxDart 2.02 ms

Peak memory Tie

Native Dart 17.5 MB
FxDart 18.3 MB

N = 1,000,000

Time Tie

Native Dart 717.6 ms
FxDart 722.8 ms

Peak memory Tie

Native Dart 238.8 MB
FxDart 239.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.