Skip to content

Itertools

Developer UtilitiesUtilitiesRust

What it is

Itertools extends Rust's iterators with dozens of adaptors the standard library omits: chunking, grouping, cartesian products, deduplication and more.

Import the Itertools trait to add methods to every existing iterator. Everything stays lazy and composes with the standard adaptors.

Installation

cargo add itertools

Getting started

The smallest useful thing you can do with it, and what each part means.

The adaptors you will actually use
use itertools::Itertools;

// Join without a manual fold.
let list = names.iter().join(", ");

// Group consecutive equal keys (sort first for global grouping).
for (year, books) in books.iter().chunk_by(|b| b.year).into_iter() {
    println!("{year}: {}", books.count());
}

// Deduplicate while preserving order.
let unique: Vec<_> = ids.into_iter().unique().collect();

// Sliding windows and fixed chunks.
for pair in prices.iter().tuple_windows::<(_, _)>() {
    println!("change: {}", pair.1 - pair.0);
}

// Split successes from failures in one pass.
let (ok, failed): (Vec<_>, Vec<_>) = results.into_iter().partition_result();
chunk_by only groups adjacent items, which surprises people — sort by the key first if you want global grouping. partition_result is excellent for handling a batch of fallible operations.

Advanced usage

Where the library earns its place over a simpler alternative.

Combinatorics and fallible collection
// Every pair, without repeats.
for (a, b) in items.iter().tuple_combinations() {
    compare(a, b);
}

// Cartesian product across two sets.
let grid: Vec<_> = rows.iter().cartesian_product(cols.iter()).collect();

// Stop at the first error and return it.
let parsed: Result<Vec<i32>, _> = inputs.iter()
    .map(|s| s.parse::<i32>())
    .try_collect();

// Exactly one match, or an error either way.
let only = matches.into_iter().exactly_one()?;
try_collect short-circuits on the first failure, which is usually what you want when parsing a batch — the standard collect into Result does the same but reads less clearly in a chain.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

chunk_by produces more groups than expected
It groups consecutive items only. Sort by the same key first.
cannot borrow while iterating
Several adaptors return borrowed lazy iterators. Collect into a Vec before mutating the source.

Best practices

  • Sort before chunk_by unless you genuinely want runs of adjacent items.
  • Prefer these adaptors over hand-written loops — they are lazy and allocate less.
  • Check std first; several former Itertools methods are now stable there.
  • Use exactly_one when a query should return precisely one result; it makes the invariant explicit.

Background

Why it exists, and what it was reacting to.

The standard Iterator trait is deliberately minimal. Itertools collects the combinators that repeatedly prove useful without meriting inclusion in std.