Skip to content

Vec::retain

Vec methods · Collections

Level: reference · for working programmers

One line: Keep the elements a predicate approves, in one pass.

pub fn retain<F>(&mut self, f: F)
where
    F: FnMut(&T) -> bool,

Stable since 1.0.0.

Note the direction: retain keeps what returns true. A predicate written as if it named what to remove silently inverts the whole operation, and nothing warns.

One O(n) pass, order preserved. That is why it is the right answer instead of a loop calling remove, which is O(n²) and has the shifting-index bug to get wrong as well.

Each element is visited exactly once, in order, so a counter in the closure is a reliable index — and a HashSet in the closure turns it into a first-occurrence deduplicator, which is the thing dedup cannot do because it only sees consecutive runs.

The predicate takes &T. For &mut T, use retain_mut.

Elements that fail are dropped as the pass goes. If you want them back, extract_if is retain's mirror image.

Example

vec_retain.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    // Keeps the elements the predicate approves — note "retain", not "remove".
    let mut v = vec![1, 2, 3, 4, 5, 6];
    v.retain(|n| n % 2 == 0);
    println!("{v:?}");

    // Order is preserved and it is a single O(n) pass, which is what makes it
    // the right answer instead of a loop calling remove().
    let mut words = vec!["a", "", "bb", "", "ccc"];
    words.retain(|w| !w.is_empty());
    println!("{words:?}");

    // The predicate takes &T, so it can read but not change.
    let mut v = vec![String::from("keep"), String::from("drop this")];
    v.retain(|s| !s.contains(' '));
    println!("{v:?}");

    // Visited in order, exactly once each — so a counter works as an index.
    let mut seen = vec![];
    let mut v = vec![10, 20, 30];
    v.retain(|n| { seen.push(*n); true });
    println!("visit order: {seen:?}");

    // Deduplicating with a set the predicate closes over. dedup() only
    // removes CONSECUTIVE duplicates; this removes all of them.
    let mut seen = std::collections::HashSet::new();
    let mut v = vec![3, 1, 3, 2, 1, 3];
    v.retain(|n| seen.insert(*n));
    println!("first occurrence of each: {v:?}");

    // Dropped elements are dropped as it goes.
    struct Noisy(u8);
    impl Drop for Noisy {
        fn drop(&mut self) { println!("  dropping {}", self.0); }
    }
    let mut v = vec![Noisy(1), Noisy(2), Noisy(3)];
    println!("retain(even):");
    v.retain(|n| n.0 % 2 == 0);
    println!("  survivor: {}", v[0].0);
}

Verified output of vec_retain.rs — regenerated by tools/run_examples.py, never hand-typed.

[2, 4, 6]
["a", "bb", "ccc"]
["keep"]
visit order: [10, 20, 30]
first occurrence of each: [3, 1, 2]
retain(even):
  dropping 1
  dropping 3
  survivor: 2
  dropping 2

See also

Vec::retain in the standard library ↗