itertools & rand
itertools extends the iterator ecosystem with combinators std lacks. rand provides reproducible, testable randomness for simulations, sampling, and IDs.
Recipe
itertools = "0.14"
rand = "0.9"use itertools::Itertools;
fn main() {
let v = vec![1, 2, 3, 4];
let pairs: Vec<_> = v.iter().tuple_windows().collect();
assert_eq!(pairs, vec![(&1, &2), (&2, &3), (&3, &4)]);
}use rand::Rng;
fn sample_id() -> u64 {
rand::rng().random_range(1_000_000..9_999_999)
}When to reach for this:
- Chunking, grouping, and cartesian products in ETL
- Shuffling test fixtures
- Game logic, Monte Carlo, load test data
Working Example
use itertools::iproduct;
use rand::seq::SliceRandom;
fn all_pairs(ids: &[u32]) -> Vec<(u32, u32)> {
iproduct!(ids.iter(), ids.iter())
.map(|(&a, &b)| (a, b))
.filter(|(a, b)| a < b)
.collect()
}
fn shuffled(mut items: Vec<&str>) -> Vec<&str> {
items.shuffle(&mut rand::rng());
items
}What this demonstrates:
iproduct!replaces nested loopstuple_windowsfor sliding viewsSliceRandomfor unbiased shuffles
Deep Dive
itertools Highlights
| Adapter | Use |
|---|---|
group_by | Run-length style grouping |
chunks / batch | Fixed-size batches |
unique | Dedup in iterator pipeline |
collect_vec | Ergonomic collect (extension trait) |
Reproducible RNG
use rand::SeedableRng;
use rand::rngs::StdRng;
let mut rng = StdRng::seed_from_u64(42);
let n: u32 = rng.random_range(0..100);Seed in tests for deterministic output.
Gotchas
- rand in security contexts -
thread_rngis not crypto. Fix:rand_core+ringor OS RNG for tokens. - Collecting infinite iterators - hangs. Fix:
take(n)beforecollect. - itertools in public APIs - couples consumers to crate. Fix: return
Vecorimpl Iteratorwhere possible. - Bias in
random_range- use library ranges, not%on integers. - Large cartesian products - memory explosion. Fix: stream with
for_eachinstead ofcollect.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Manual loops | Tiny logic | Combinatorial pipelines |
uuid crate | Unique IDs | Statistical sampling |
nanoid | URL-safe IDs | Scientific RNG |
FAQs
rand 0.8 vs 0.9?
New projects use 0.9 API (rng() entry point). Align workspace on one version.
Parallel iterators?
Use rayon for parallel collect; itertools stays sequential.
Shuffle for load tests?
Shuffle input ids, then take(n) for representative samples.
Does itertools allocate?
Most adapters are lazy; collect allocates the result container.
Related
- Iterator adapters
- rayon - parallel collect
- Collections basics
- Essential Crates Best Practices
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.