Vec<T> in Depth
retain() and dedup()
Vec<T> provides two linear-time ($O(n)$), in-place compaction families that remove unwanted elements in a single pass without reallocating the vector: .retain() / .retain_mut() for predicate filtering, and .dedup() / .dedup_by() / .dedup_by_key() for collapsing consecutive duplicates.
In-Place Filtering with retain() and retain_mut()
impl<T> Vec<T> {
pub fn retain<F>(&mut self, f: F)
where
F: FnMut(&T) -> bool;
pub fn retain_mut<F>(&mut self, f: F)
where
F: FnMut(&mut T) -> bool;
}
v.retain(f)visits each element in order (0..len), drops elements wheref(&elem)returnsfalse, and shifts kept elements left in a single $O(n)$ pass.v.retain_mut(f)passes&mut Tto the closure so you can both mutate kept elements in place and decide whether to keep them in one pass:
fn main() {
let mut timers = vec![3_u32, 1, 4, 1, 2];
// Decrement each timer by 1 and keep only timers that have not reached 0:
timers.retain_mut(|t| {
*t -= 1;
*t > 0
});
println!("Active timers after tick: {timers:?}");
}
Active timers after tick: [2, 3, 1]
Collapsing Consecutive Duplicates with dedup(), dedup_by(), and dedup_by_key()
impl<T: PartialEq> Vec<T> {
pub fn dedup(&mut self);
}
impl<T> Vec<T> {
pub fn dedup_by<F>(&mut self, same_bucket: F)
where
F: FnMut(&mut T, &mut T) -> bool;
pub fn dedup_by_key<F, K>(&mut self, key: F)
where
F: FnMut(&mut T) -> K,
K: PartialEq;
}
Important: .dedup() only removes adjacent (consecutive) duplicates in $O(n)$ time. To remove all duplicates across an unsorted vector, sort the vector first (v.sort_unstable()) and then call v.dedup():
Unsorted `[1, 2, 1, 2]`:
├── v.dedup() ──> `[1, 2, 1, 2]` (no adjacent duplicates!)
└── v.sort_unstable(); v.dedup(); ──> `[1, 2]` (all duplicates removed)
fn main() {
// 1. Removing consecutive duplicates only:
let mut consecutive = vec![1, 1, 2, 3, 3, 3, 2, 2];
consecutive.dedup();
println!("Consecutive dedup: {consecutive:?}");
// 2. Removing ALL duplicates by sorting first:
let mut all_unique = vec![30, 10, 20, 30, 10];
all_unique.sort_unstable();
all_unique.dedup();
println!("Sorted + dedup: {all_unique:?}");
// 3. Merging adjacent elements in place with `dedup_by`
// (Note: in `dedup_by(|a, b| ...)`, `b` is the earlier kept element and `a` is the next element):
let mut runs = vec![("cpu", 10), ("cpu", 15), ("mem", 40)];
runs.dedup_by(|next, kept| {
if next.0 == kept.0 {
kept.1 += next.1;
true // Drop `next` after accumulating its count into `kept`
} else {
false
}
});
println!("Merged runs: {runs:?}");
}
Consecutive dedup: [1, 2, 3, 2]
Sorted + dedup: [10, 20, 30]
Merged runs: [("cpu", 25), ("mem", 40)]