코호트 리텐션 테이블
요구사항
각 사용자(데이터는 코드 안에 있음)는 가입월과 활동한 월의 목록을 갖고 있습니다. 사용자를 가입월 기준 코호트로 묶고, 그 이후의 각 월마다 코호트 중 몇 퍼센트가 여전히 활동 중이었는지 출력하세요 — 코호트당 한 줄씩, 오래된 순서로 정렬합니다. 두 버전 모두 예상 출력 아래에 표시된 테이블을 출력해야 합니다.
예상 출력
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%
나란히 보기
네이티브 Dart
FxDart
차이가 나는 이유
리텐션 테이블은 파이프라인 속의 파이프라인입니다: 바깥쪽은 코호트,
안쪽은 월입니다. FxDart에서는 두 계층 모두 표현식입니다 — 코호트에
대해서는 groupBy → sortBy → map이
적용되고, 각 행 안에서는 dropWhile이 가입월까지의 달을
건너뛴 뒤 filter + size가 여전히 활동 중인
사용자 수를 셉니다. 네이티브 버전은 계층마다 가변 누산 리스트
(rows, cells)가 필요하고, 이를 엮기 위해 두
겹의 중첩 for 루프가 필요합니다. 실제 리텐션 로직은
동일하지만, 코드의 눈에 보이는 뼈대가 되는 대신 루프 본문 곳곳에
흩어져 있습니다.
벤치마크
N = 100
시간 무승부
최대 메모리 무승부
N = 10,000
시간 무승부
최대 메모리 무승부
N = 1,000,000
시간 무승부
최대 메모리 무승부
막대는 사이드별로 새 프로세스에서 반복 측정한 중앙값입니다(작은 N은 타이머 해상도를 위해 배치 처리). 두 사이드가 서로 5% 이내이거나 — 사람이 지각할 수 없는 차이인 0.6ms 이내이면 — 무승부로 칩니다. 상대 차이가 근소한 경우는 최대 5회까지 다시 측정합니다. 앱에서는 어느 막대가 짧든 몇 밀리초 이하의 차이는 사용자에게 보이지 않습니다. 메모리는 프로세스 최대 RSS입니다. Dart VM과 데이터셋은 양쪽이 동일하므로, 두 막대의 차이가 곧 파이프라인 자체가 붙들고 있는 양입니다.