Need to split a collection into two groups based on a condition? Skip the manual loop — Iterator::partition does it in one call.
The manual way
Without partition, you’d loop and push into two separate vectors:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut evens = Vec::new();
let mut odds = Vec::new();
for n in numbers {
if n % 2 == 0 {
evens.push(n);
} else {
odds.push(n);
}
}
assert_eq!(evens, vec![2, 4, 6, 8]);
assert_eq!(odds, vec![1, 3, 5, 7]);
|
It works, but it’s a lot of ceremony for a simple split.
Enter partition
Iterator::partition collects into two collections in a single pass. Items where the predicate returns true go left, false goes right:
1
2
3
4
5
6
7
8
| let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8];
let (evens, odds): (Vec<_>, Vec<_>) = numbers
.iter()
.partition(|&&n| n % 2 == 0);
assert_eq!(evens, vec![&2, &4, &6, &8]);
assert_eq!(odds, vec![&1, &3, &5, &7]);
|
The type annotation (Vec<_>, Vec<_>) is required — Rust needs to know what collections to build. You can partition into any type that implements Default + Extend, not just Vec.
Owned values with into_iter
Use into_iter() when you want owned values instead of references:
1
2
3
4
5
6
7
8
9
10
11
| let files = vec![
"main.rs", "lib.rs", "test_utils.rs",
"README.md", "CHANGELOG.md",
];
let (rust_files, other_files): (Vec<_>, Vec<_>) = files
.into_iter()
.partition(|f| f.ends_with(".rs"));
assert_eq!(rust_files, vec!["main.rs", "lib.rs", "test_utils.rs"]);
assert_eq!(other_files, vec!["README.md", "CHANGELOG.md"]);
|
A practical use: triaging results
partition pairs beautifully with Result to separate successes from failures:
1
2
3
4
5
6
7
8
9
10
11
12
| let inputs = vec!["42", "not_a_number", "7", "oops", "13"];
let (oks, errs): (Vec<_>, Vec<_>) = inputs
.iter()
.map(|s| s.parse::<i32>())
.partition(Result::is_ok);
let values: Vec<i32> = oks.into_iter().map(Result::unwrap).collect();
let failures: Vec<_> = errs.into_iter().map(Result::unwrap_err).collect();
assert_eq!(values, vec![42, 7, 13]);
assert_eq!(failures.len(), 2);
|
partition has been stable since Rust 1.0 — one of those hidden gems that’s been there all along. Anytime you reach for a loop to split items into two buckets, reach for partition instead.