measureRetention static method
Bucket review events by interval and compute retained/lapsed ratio.
A review is "retained" if quality ≥ 3 (Hard or better).
Implementation
static List<RetentionBucket> measureRetention(List<ReviewLog> logs) {
// Assign each review to the nearest bucket.
final bucketCounts = <int, int>{};
final bucketRetained = <int, int>{};
for (final b in retentionBuckets) {
bucketCounts[b] = 0;
bucketRetained[b] = 0;
}
for (final log in logs) {
final bucket = _nearestBucket(log.elapsedDays);
bucketCounts[bucket] = (bucketCounts[bucket] ?? 0) + 1;
if (log.quality >= 3) {
bucketRetained[bucket] = (bucketRetained[bucket] ?? 0) + 1;
}
}
return retentionBuckets
.map(
(b) => RetentionBucket(
intervalDays: b,
totalReviews: bucketCounts[b]!,
retainedCount: bucketRetained[b]!,
),
)
.where((b) => b.totalReviews > 0)
.toList();
}