Finding and removing an element in a vec

Hello, I want to do find an element in a vec and remove it.

Here is how I do it.

let mut some_vec = vec![0, 10, 20, 30];
if let Some(index) = some_vec.iter().find(|value| **value == 10) {
    some_vec.swap_remove(*index);
}

However, I get this warning

warning: cannot borrow `some_vec` as mutable because it is also borrowed as immutable

I skim throught https://github.com/rust-lang/rust/issues/59159 and decided to try the following, but I still get the same warning.

let mut some_vec = vec![0, 10, 20, 30];
let index = some_vec.iter().find(|value| **value == 10).clone();
if let Some(index) = index {
    some_vec.swap_remove(*index);
}

So, I'm a bit confused. In the later, I tought that it would be fine since I'm using clone. How could I get rid of this warning?

You can find a playground with both approaches.

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=6a04a05b3c2b89f2a66e50a2e139025b

1 Like

Instead of find, which returns a reference to the matching value, I think you want position, which returns the index of the matching value:

if let Some(index) = some_vec.iter().position(|value| *value == 10) {
    some_vec.swap_remove(index);
}
4 Likes

One simple way to do it is to retain all elements that don't have that value:

    let mut some_vec = vec![0, 10, 20, 30];
    some_vec.retain(|value| *value != 10);

Note that in case there are several elements with value 10, this will remove all of them, which might or might not be what you want.

5 Likes

While I think the answer about find vs. position is correct for your intention, I thought I'd address this:

Cloning an Option<&T> gets you another Option<&T>, with the same borrowed lifetime. Instead, you can use .cloned() to get an independent Option<T>.

Another possibility for Copy types is to destructure the reference when you match it:

if let Some(&index) = index { ... }
3 Likes

That is exactly what I wanted. I was confused. Thanks.

There is also a nightly method to achieve directly what you want — remove_item: (requires #![feature(vec_remove_item)])

let mut some_vec = vec![0, 10, 20, 30];
some_vec.remove_item(&10);

(playground)

1 Like

That method is unlikely to be stabilized, because it can't work for a common case of:

let mut some_vec = vec![0, 10, 20, 30];
let some_item = &vec[1];
some_vec.remove_item(some_item);

and it's actually behaving like remove_first_item:

let mut some_vec = vec![0, 10, 10, 10];
some_vec.remove_item(&10);
assert_eq!(10, vec[1]);

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.