#232 Jun 30, 2026

232. Iterator::partition — Split Into Two Collections in One Pass

Splitting items into “matches” and “the rest” with two .filter() calls walks the list twice. partition does it in a single pass.

The two-filter version reads fine but iterates the whole thing twice, once per predicate:

1
2
3
4
let nums = [1, 2, 3, 4, 5, 6, 7, 8];

let even: Vec<i32> = nums.iter().copied().filter(|n| n % 2 == 0).collect();
let odd:  Vec<i32> = nums.iter().copied().filter(|n| n % 2 != 0).collect();

The manual loop is one pass but needs two mutable Vecs and the bookkeeping to feed them. partition is the one-pass version with none of the noise — true items go left, false items go right:

1
2
3
4
5
let nums = [1, 2, 3, 4, 5, 6, 7, 8];

let (even, odd): (Vec<i32>, Vec<i32>) = nums.iter().partition(|&&n| n % 2 == 0);
assert_eq!(even, [2, 4, 6, 8]);
assert_eq!(odd,  [1, 3, 5, 7]);

The collection types come from the annotation, and they don’t have to be Vec or even match each other — any pair that implements FromIterator works:

1
2
3
4
5
6
let words = ["hi", "hello", "yo", "howdy"];

let (long, short): (Vec<&str>, Vec<&str>) =
    words.into_iter().partition(|s| s.len() > 3);
assert_eq!(long,  ["hello", "howdy"]);
assert_eq!(short, ["hi", "yo"]);

Whenever you catch yourself filtering the same iterator twice with opposite conditions, that’s a partition.

← Previous 231. slice::chunk_by — Group Consecutive Elements Without the Index Bookkeeping Next → 233. str::split_terminator — Split Without the Trailing Empty String