Home

Awesome

Iterator Chunking

A TC39 proposal to consume an iterator as either overlapping or non-overlapping subsequences of configurable size.

Stage: 1

Specification: https://tc39.es/proposal-iterator-chunking/

presentations to committee

motivation

It can be useful to consume a stream by more than one value at a time. For example, certain algorithms require looking at adjacent elements.

chunking

This is commonly solved for non-overlapping subsequences with a "chunking" method that works like the following:

const digits = () => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].values();

let chunksOf2 = Array.from(digits().chunks(2));
// [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9] ]

let chunksOf3 = Array.from(digits().chunks(3));
// [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9] ]

let chunksOf4 = Array.from(digits().chunks(4));
// [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9] ]

use cases for chunking

sliding window

When overlapping sequences are needed, this is commonly called a "sliding window".

let windowsOf2 = Array.from(digits().windows(2));
// [ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9] ]

let windowsOf3 = Array.from(digits().windows(3));
// [ [0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7], [6, 7, 8], [7, 8, 9] ]

let windowsOf4 = Array.from(digits().windows(4));
// [ [0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9] ]

use cases for sliding windows

prior art

other languages

languagelibrarychunkswindowschunks of 0?truncates windows?
C++std::ranges::viewschunkslideundefined behaviorno
Clojurecorepartitionpartitioninfinite empty listswhen insufficient padding;<br/>terminates after 1
ElmList.ExtragroupsOfgroupsOfWithStepempty listno
HaskellsplitchunksOfdivvyinfinite empty listsyes
JavaStreamGatherers.windowFixedGatherers.windowSlidingthrowsno, step not configurable
KotlinIterablechunkedwindowedthrowsconfigurable via parameter
.NETSystem.LinqEnumerable.Chunk--throwsN/A
PHParrayarray_chunk--throwsN/A
Pythonitertools (3.12)batched--??N/A
Pythonmore-itertoolsgrouperwindowedempty iteratorno, mandatory fill value
RubyEnumerableeach_sliceeach_consthrowsno, step not configurable
RustIteratorarray_chunksmap_windowspanicsno, step not configurable
Rustslicechunkswindowspanicsno, step not configurable
ScalaSeqgroupedslidingthrowsyes
SwiftSequence----N/AN/A

JS libraries

librarychunkswindowschunks of 0?truncates windows?
chunkchunk--coerces 0 to false 😞N/A
extra-iterablechunkchunkinfinite empty arraysyes
iter-opspage--throwsN/A
iter-toolsbatchwindow, windowAhead, windowBehindthrowsoptionally
iterablefuchunk--collects everything into a single arrayN/A
itertools-tschunkwisechunkwiseOverlapthrowsyes
Lodash / Underscorechunk--infinite empty arraysN/A
RamdasplitEveryapertureinfinite empty arraysno
sequencychunk--throwsN/A
wuchunk--collects everything into a single arrayN/A