Skip to content

tc39/proposal-iterator-chunking

Iterator Chunking

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

Stage: 2.7

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:

constdigits=()=>[0,1,2,3,4,5,6,7,8,9].values();letchunksOf2=Array.from(digits().chunks(2));// [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9] ]letchunksOf3=Array.from(digits().chunks(3));// [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9] ]letchunksOf4=Array.from(digits().chunks(4));// [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9] ]

use cases for chunking

  • pagination
  • columnar/grid layouts, such as calendars
  • batch/stream processing
  • matrix operations
  • formatting/encoding
  • bucketing (using a computed chunk size, for iterators of known size)

sliding window

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

letwindowsOf2=Array.from(digits().windows(2));// [ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9] ]letwindowsOf3=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] ]letwindowsOf4=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

  • running/continuous computations, such as averages
  • context-sensitive algorithms, such as pairwise comparisons
  • carousels and their analogues (when applied to an infinite cycle)

prior art

other languages

languagelibrarychunkswindowschunks of 0?truncates windows?
C++std::ranges::viewschunkslideundefined behaviorno
Clojurecorepartitionpartitioninfinite empty listswhen insufficient padding;
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

About

a proposal to add a method to iterators for producing an iterator of its subsequences

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks