foldByOrSkip
foldBy처럼 키별로 접되, 키가 null이면 그 원소를 건너뜁니다 — 콜백 하나가 선택과 분류를 겸합니다.
강의
foldByOrSkip(key, seed, f, xs)는
filter +
foldBy를 하나의 즉시(strict)
호출로 쓴 것입니다. foldBy가 보장하는 것은 그대로입니다 —
seed는 키마다 시작점이지 키를 가로질러 누적되지 않고, 키는
처음 등장한 순서로 나오며, 맵은 원소당 한 번만 조회됩니다. 한 가지
비틀림은 키 함수입니다: null을 반환하면 "이 원소는
건너뛴다"는 뜻으로, filter_map 형태이며
takeUniqBy가 같은 형태를
씁니다.
기본은 filter(...).foldBy(...)로 쓰십시오. 이름 붙은 두
단계가 두 질문을 겸하는 콜백 하나보다 잘 읽히고, 여기서는 그 두 질문이
대개 무관합니다 — 날짜 범위와 카테고리는 같은 생각이 아닙니다. 이
연산자가 존재하는 이유는 하나뿐이며, 그게 무엇인지 아는 편이 좋습니다.
존재 이유: 컴파일러가 볼 수 없는 술어
filter는 지연 단계라 술어를 이터레이터의 필드에
담아 둡니다. AOT 컴파일러는 필드 너머를 보지 못하므로 그 술어는 결코
인라인되지 않습니다 — 원소마다 실제 간접 호출을 내고, 본문이 주변 루프에
녹아들지도 못합니다. foldBy에는 그 문제가 없습니다. 즉시
연산자라 콜백이 매개변수이고 호출부에 인라인됩니다. 앞에 붙은 필터가
비용입니다.
foldByOrSkip은 그 판정을 매개변수인 키 안으로 옮깁니다.
거래 100만 건, 12개월 중 한 달만 남기는 조건, AOT 기준:
| 표현 | 시간 |
|---|---|
filter().foldBy() | 14.5 ms |
foldByOrSkip(…) | 12.6 ms |
| 손으로 쓴 루프 | 11.3 ms |
두 표현과 두 막대 모두 월별 카테고리 리포트 페이지에 있습니다 — 같은 파이프라인을 쓰는 두 방식의 차이가 그 페이지가 말하려는 바라서, 막대를 둘이 아니라 셋 싣는 두 페이지 중 하나입니다.
데모 1 · 7월의 카테고리별 지출
데모 2 · seed, 건너뛰기, 그리고 fold가 보는 것
직접 해보기
연습: 고장 난 행을 빼고 센서별 최고 측정값 구하기.
foldBy — 이 연산자가 딛고 선 접기 ·
filter — 흡수한 단계 ·
takeUniqBy — filter + uniqBy + take에 대한 같은 발상 ·
성능 — 콜백 바닥값이 어디서 오는지