263: Fixed-Size Chunks Iteration
Functional Programming
Tutorial
The Problem
Batch processing is fundamental to systems programming: sending data in fixed-size network packets, processing database rows in pages, dividing work among threads, or encoding binary data in base64 groups of 3 bytes. The chunks(n) method partitions a slice into non-overlapping sub-slices of at most n elements, handling the remainder (a possibly smaller final chunk) automatically.
🎯 Learning Outcomes
chunks(n) divides a slice into non-overlapping groups of at most n elementschunks() from chunks_exact(): the latter excludes the remainderchunks_exact() separately for clean batch+remainder logicCode Example
#![allow(clippy::all)]
//! 263. Fixed-size chunks iteration
//!
//! `chunks(n)` splits a slice into non-overlapping sub-slices of at most n elements.
#[cfg(test)]
mod tests {
#[test]
fn test_chunks_basic() {
let data = [1i32, 2, 3, 4, 5];
let chunks: Vec<&[i32]> = data.chunks(2).collect();
assert_eq!(chunks.len(), 3);
assert_eq!(chunks[0], &[1, 2]);
assert_eq!(chunks[2], &[5]);
}
#[test]
fn test_chunks_exact_remainder() {
let data = [1i32, 2, 3, 4, 5];
let exact = data.chunks_exact(2);
assert_eq!(exact.remainder(), &[5]);
}
#[test]
fn test_chunks_divisible() {
let data = [1i32, 2, 3, 4];
let chunks: Vec<_> = data.chunks(2).collect();
assert_eq!(chunks.len(), 2);
assert!(chunks.iter().all(|c| c.len() == 2));
}
}Key Differences
chunks_exact() + .remainder() to separate full chunks from the tail; OCaml requires manual logic.&[T] slices; OCaml creates new sub-lists or arrays.chunks() is built into Rust's slice API; OCaml requires third-party libraries or custom code.OCaml Approach
OCaml lacks a standard chunks function on lists. The standard approach uses List.filteri with modular arithmetic or a recursive accumulator:
let rec chunks n lst = match lst with
| [] -> []
| _ ->
let (h, t) = (List.filteri (fun i _ -> i < n) lst,
List.filteri (fun i _ -> i >= n) lst) in
h :: chunks n t
For arrays, Array.sub arr (i * n) n achieves the same but allocates new arrays.
Full Source
#![allow(clippy::all)]
//! 263. Fixed-size chunks iteration
//!
//! `chunks(n)` splits a slice into non-overlapping sub-slices of at most n elements.
#[cfg(test)]
mod tests {
#[test]
fn test_chunks_basic() {
let data = [1i32, 2, 3, 4, 5];
let chunks: Vec<&[i32]> = data.chunks(2).collect();
assert_eq!(chunks.len(), 3);
assert_eq!(chunks[0], &[1, 2]);
assert_eq!(chunks[2], &[5]);
}
#[test]
fn test_chunks_exact_remainder() {
let data = [1i32, 2, 3, 4, 5];
let exact = data.chunks_exact(2);
assert_eq!(exact.remainder(), &[5]);
}
#[test]
fn test_chunks_divisible() {
let data = [1i32, 2, 3, 4];
let chunks: Vec<_> = data.chunks(2).collect();
assert_eq!(chunks.len(), 2);
assert!(chunks.iter().all(|c| c.len() == 2));
}
}
✓ Tests
Rust test suite
#[cfg(test)]
mod tests {
#[test]
fn test_chunks_basic() {
let data = [1i32, 2, 3, 4, 5];
let chunks: Vec<&[i32]> = data.chunks(2).collect();
assert_eq!(chunks.len(), 3);
assert_eq!(chunks[0], &[1, 2]);
assert_eq!(chunks[2], &[5]);
}
#[test]
fn test_chunks_exact_remainder() {
let data = [1i32, 2, 3, 4, 5];
let exact = data.chunks_exact(2);
assert_eq!(exact.remainder(), &[5]);
}
#[test]
fn test_chunks_divisible() {
let data = [1i32, 2, 3, 4];
let chunks: Vec<_> = data.chunks(2).collect();
assert_eq!(chunks.len(), 2);
assert!(chunks.iter().all(|c| c.len() == 2));
}
}
Exercises
chunks(3) to implement a simple base64 encoder that processes three bytes at a time and handles padding for the remainder.Vec<i32> into N approximately equal chunks and compute the sum of each chunk in parallel using threads.