Checkpoint: Lazy Batches

The Course
•
3 min read

A batch generator groups an iterable into arrays of at most size items. It validates size as a positive integer, yields a full batch when ready, then yields a final short batch if there is one. Empty input yields nothing.

Each yielded batch must be a distinct array. Reusing and clearing the same array would let later work change batches that a caller already kept. This is an ownership contract, not just a formatting detail.

The generator’s body starts on consumption, so invalid size is reported when next is called or a loop begins, not necessarily at the function call itself. Document that timing. You can choose an eager wrapper if callers need validation at construction; do not imply your generator validates sooner than it does.

Predict, run, and explain

Write the output and trace the important state changes before checking it. Then run the program. Each editor is independent. Async examples end with main() so this editor waits for their work.

Predict, then run JavaScript
function* values() {
  yield 1;
  yield 2;
  yield 3;
}

const iterator = values();

console.log(iterator.next().value);
console.log([...iterator].join(","));
Check your prediction
1
2,3

Acceptance cases before you code

Write a small test plan before implementing batch boundaries and ownership. These cases extend the brief; they are not a second worked solution. Predict the expected behavior independently, then test through the public function. A good ordinary example and a good boundary example should catch different possible mistakes.

Case to tryWhat your result should demonstrate
Empty sourceYield no batch
Final short groupYield it once without a trailing empty group
Retained batchesChanging one must not change another batch array

After the core task passes, deliberately break one rule and identify the case that notices it. Restore the implementation and explain the failure in terms of the contract, not the number of assertions. If a case requires a concept you have not recalled, revisit the relevant lesson before opening the solution.

Your turn

Exercise

Checkpoint: Lazy Batches: practise

Implement batches(values, size). For [1,2,3,4,5] and size 2, print 1,2 then 3,4 then 5. Do not yield an empty final batch. Retained batches must not share the same array.

Your workspace JavaScript
// Validate inside the generator, collect a batch, then replace the batch array after yielding.
Hint 1: the idea

A fresh array after each yield preserves earlier batches.

Hint 2: a first step

After a full batch is yielded, assign a new empty array rather than clearing the old one.

Show one solution
function* batches(values, size) {
  if (!Number.isInteger(size) || size < 1) {
    throw new RangeError("Invalid size");
  }

  let batch = [];

  for (const value of values) {
    batch.push(value);

    if (batch.length === size) {
      yield batch;
      batch = [];
    }
  }

  if (batch.length) {
    yield batch;
  }
}

for (const batch of batches([1, 2, 3, 4, 5], 2)) {
  console.log(batch.join(","));
}
1,2
3,4
5

Explain why the implementation meets the stated contract. Which part is enforced by the language or checker, and which part needs behavioral evidence?

Change it and test it

Test empty input, size 1, a size larger than the source and invalid sizes. Keep two output arrays and assert they are different references. Then use a generator with finally as the source and break early to verify cleanup propagates.

Was this article helpful?

Your response is saved on this device.