Search code examples
rustvector

How can I retain vector elements with their original index?


If I have a Vec I can iterate over elements using an index via v.iter().enumerate(), and I can remove elements via v.retain(). Is there a way to do both at once?

In this case the index could no longer be used to access the element - it would be the index of the element before the loop was started.

I can implement this myself but to be as efficient as .retain() I'd need to use unsafe, which I'd like to avoid.

This is the result I want:

let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 4, 7, 8];

v.iter()
    .retain_with_index(|(index, item)| (index % 2 == 0) || item == 4);

assert(v == vec![1, 3, 4, 5, 4, 7]);

Solution

  • I found essentially the same question on the Rust User's Forum. They suggested this solution, which isn't too bad:

    let mut index = 0;
    v.retain(|item| {
        index += 1;
        ((index - 1) % 2 == 0) || item == 4
    });
    

    At the time it wasn't a valid solution because the iteration order of retain() was not guaranteed, but happily for me someone in that thread documented the order so now it is. :-)