foldByOrSkip
Folds by key like foldBy, except a null key skips the element — so one callback both selects and buckets.
Lecture
foldByOrSkip(key, seed, f, xs) is
filter +
foldBy written as a single strict
call. Everything foldBy guarantees still holds: [seed] starts
every key rather than running across them, keys come out in first-seen
order, and the map is probed once per element. The one twist is the key
function — returning null means "skip this element", the same
filter_map shape
takeUniqBy uses.
Write filter(...).foldBy(...) by default. Two named steps read
better than one callback answering two questions, and here the two
questions are usually unrelated — a date range and a category are not the
same thought. This operator exists for one reason, and it is worth knowing
what it is.
Why it exists: the predicate the compiler cannot see
filter is a lazy stage, so it keeps its predicate in
an iterator field. The AOT compiler cannot see through a field, so that
predicate never inlines — every element pays a real indirect call, and its
body is never fused into the loop around it. foldBy does not
have that problem: it is strict, so its callbacks are parameters and get
inlined into the call site. The filter in front of it is what costs.
foldByOrSkip moves the test into the key, which is a
parameter. Measured over 1,000,000 transactions, AOT, keeping one month in
twelve:
| Spelling | Time |
|---|---|
filter().foldBy() | 14.5 ms |
foldByOrSkip(…) | 12.6 ms |
| a hand-written loop | 11.3 ms |
Both spellings, and both bars, are on Monthly category report, sorted by spend — one of the two comparison pages that publish three bars instead of two, because the gap between two ways of writing the same pipeline is the point they make.
Demo 1 · July's spend per category
Demo 2 · The seed, the skip, and what the fold sees
Try it yourself
Exercise: the highest reading per sensor, ignoring faulty rows.
foldBy — the fold this builds on ·
filter — the stage it absorbs ·
takeUniqBy — the same idea for filter + uniqBy + take ·
Performance — where the callback floor comes from