093 — Windows and Chunks
Tutorial
The Problem
Use Rust's slice methods .windows(n) and .chunks(n) to create overlapping and non-overlapping subslice iterators. Demonstrate that windows slides one element at a time (producing len - n + 1 windows) while chunks partitions without overlap (last chunk may be shorter). Compare with OCaml's manual recursive implementations.
🎯 Learning Outcomes
slice.windows(n) for overlapping n-element viewsslice.chunks(n) for non-overlapping n-element partitions&[T] — zero-copy subslice referenceschunks_exact(n) when trailing partial chunks should be excludedCode Example
#![allow(clippy::all)]
// 093: Windows and Chunks
#[cfg(test)]
mod tests {
#[test]
fn test_windows() {
let v = vec![1, 2, 3, 4, 5];
let w: Vec<&[i32]> = v.windows(3).collect();
assert_eq!(w, vec![&[1, 2, 3][..], &[2, 3, 4][..], &[3, 4, 5][..]]);
}
#[test]
fn test_windows_2() {
let v = vec![1, 2, 3];
let w: Vec<&[i32]> = v.windows(2).collect();
assert_eq!(w, vec![&[1, 2][..], &[2, 3][..]]);
}
#[test]
fn test_chunks() {
let v = vec![1, 2, 3, 4, 5];
let c: Vec<&[i32]> = v.chunks(2).collect();
assert_eq!(c, vec![&[1, 2][..], &[3, 4][..], &[5][..]]);
}
#[test]
fn test_chunks_exact() {
let v = vec![1, 2, 3, 4, 5, 6];
let c: Vec<&[i32]> = v.chunks(3).collect();
assert_eq!(c, vec![&[1, 2, 3][..], &[4, 5, 6][..]]);
}
}Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Windows | slice.windows(n) built-in | Manual recursive function |
| Chunks | slice.chunks(n) built-in | Manual recursive function |
| Element type | &[T] (borrowed subslice) | 'a list (new list) |
| Allocation | Zero-copy | Allocates sublists |
| Exact chunks | chunks_exact(n) | Manual length check |
| String windows | s.as_bytes().windows(n) | Substring extraction |
windows is particularly useful for sliding window algorithms: computing moving averages, detecting runs, or finding maximum subarray sums. chunks is useful for batch processing: splitting work across threads or formatting data in fixed-size blocks.
OCaml Approach
OCaml has no built-in windows/chunks on lists. The recursive windows n lst takes a prefix of length n, adds it to the accumulator, and recurses on the tail. chunks n lst groups elements into sublists of size n. Both use List.rev and manual counting — more verbose than Rust's built-in methods. Array operations (Array.sub) would be closer to Rust's approach.
Full Source
#![allow(clippy::all)]
// 093: Windows and Chunks
#[cfg(test)]
mod tests {
#[test]
fn test_windows() {
let v = vec![1, 2, 3, 4, 5];
let w: Vec<&[i32]> = v.windows(3).collect();
assert_eq!(w, vec![&[1, 2, 3][..], &[2, 3, 4][..], &[3, 4, 5][..]]);
}
#[test]
fn test_windows_2() {
let v = vec![1, 2, 3];
let w: Vec<&[i32]> = v.windows(2).collect();
assert_eq!(w, vec![&[1, 2][..], &[2, 3][..]]);
}
#[test]
fn test_chunks() {
let v = vec![1, 2, 3, 4, 5];
let c: Vec<&[i32]> = v.chunks(2).collect();
assert_eq!(c, vec![&[1, 2][..], &[3, 4][..], &[5][..]]);
}
#[test]
fn test_chunks_exact() {
let v = vec![1, 2, 3, 4, 5, 6];
let c: Vec<&[i32]> = v.chunks(3).collect();
assert_eq!(c, vec![&[1, 2, 3][..], &[4, 5, 6][..]]);
}
}#[cfg(test)]
mod tests {
#[test]
fn test_windows() {
let v = vec![1, 2, 3, 4, 5];
let w: Vec<&[i32]> = v.windows(3).collect();
assert_eq!(w, vec![&[1, 2, 3][..], &[2, 3, 4][..], &[3, 4, 5][..]]);
}
#[test]
fn test_windows_2() {
let v = vec![1, 2, 3];
let w: Vec<&[i32]> = v.windows(2).collect();
assert_eq!(w, vec![&[1, 2][..], &[2, 3][..]]);
}
#[test]
fn test_chunks() {
let v = vec![1, 2, 3, 4, 5];
let c: Vec<&[i32]> = v.chunks(2).collect();
assert_eq!(c, vec![&[1, 2][..], &[3, 4][..], &[5][..]]);
}
#[test]
fn test_chunks_exact() {
let v = vec![1, 2, 3, 4, 5, 6];
let c: Vec<&[i32]> = v.chunks(3).collect();
assert_eq!(c, vec![&[1, 2, 3][..], &[4, 5, 6][..]]);
}
}
Deep Comparison
Core Insight
Windows overlap, chunks don't — both view contiguous data without copying
OCaml Approach
Rust Approach
Comparison Table
| Feature | OCaml | Rust |
|---|---|---|
| See | example.ml | example.rs |
Exercises
Vec<f64> using windows(3).windows(2) to count adjacent pairs where the second element is greater than the first (number of increases).batch_process<T, F>(items: &[T], batch_size: usize, f: F) using chunks to process items in groups.v.windows(2) to implement is_sorted(v: &[i32]) -> bool.windows_seq n lst using Seq for laziness — producing windows on demand without materialising all at once.