Tabla de retención por cohortes
Requisito
Cada usuario (los datos están en el código) tiene un mes de alta y la lista de meses en los que estuvo activo. Agrupa a los usuarios en cohortes por mes de alta y, para cada mes posterior, imprime qué porcentaje de la cohorte seguía activo —una fila por cohorte, de la más antigua a la más reciente. Ambas versiones deben imprimir la tabla que aparece bajo Salida esperada.
Salida esperada
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%
Lado a lado
Dart nativo
FxDart
Por qué difieren
Una tabla de retención es un pipeline dentro de otro pipeline: las
cohortes por fuera, los meses por dentro. En FxDart ambas capas son
expresiones —groupBy → sortBy →
map sobre las cohortes y, dentro de cada fila,
dropWhile salta los meses hasta el mes de alta antes de que
filter + size cuenten los usuarios que siguen
activos. La versión nativa necesita una lista acumuladora mutable por
capa (rows, cells) y dos bucles
for anidados para coserlas; la lógica de retención en sí es
la misma, pero está repartida por los cuerpos de los bucles en lugar de
ser la columna vertebral visible del código.
Benchmark
N = 100
Tiempo Empate
Memoria pico Empate
N = 10,000
Tiempo Empate
Memoria pico Empate
N = 1,000,000
Tiempo Empate
Memoria pico Empate
Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.