Is it possible to find an element in a Vec<T> and remove it?

11.5k views Asked by At

In Rust, is there an in built function for finding and removing elements of a vector, both simultaneously and as separate actions?

For example:

for f in factors {
    if f in list {
        list.remove(f);
    }
}

Currently, the rust documentation is still a tad confusing, so while my search as shown up nothing, I feel like there is a good chance someone else may have found it.

3

There are 3 answers

1
A.B. On BEST ANSWER

The example can be written as:

let mut list = (0..10).collect::<Vec<u32>>();
list.retain(|element| element % 2 == 0);
assert_eq!(&list[..], &[0, 2, 4, 6, 8]);

The relevant documentation can be found here: https://doc.rust-lang.org/std/vec/struct.Vec.html

0
llogiq On

You could always use an into_iter() to destructure the Vec into an iterator, filter(..) that for the element and collect() into a new Vec:

list.into_iter().filter(|e| !factors.contains(e)).collect();

You may need to specify the type of collect (which should be Vec<T> where T is the type of your element) unless you bind it into a variable of the right type.

Edit: Following A.B.'s advice, you could also write

list.retain(|e| !factors.contains(e))

Note that both would be within O(L × F) where L is the len of list and F the len of factors. For small L and/or F, this will be fine. Otherwise it may be better to convert factors into a HashSet first.

0
Paolo Falabella On

There is no simultaneous "find and remove" method, that I know of. Vec has:

  • remove is the general method to remove an element and shift all the ones that follow to fill the gap
  • swap_remove remove this element and replace it with the last (avoids all the shifting, so it's generally quicker)
  • pop removes the last element (very efficient, might not be what you need if you want to remove an element in the middle of the Vec)

you could do something like:

let mut v = vec![1, 2, 3];
// iterate through the vector and return the position for the
// first element == 2. If something is found bind it to the name
// index
if let Some(index) = v.iter().position(|&i| i == 2) {
    v.remove(index); // remove the element at the position index (2)
}

println!("{:?}", v); // prints [1, 3]