Idiomatic way to insert after a certain element in vector

Viewed 228

Consider the following code:

struct Data {
    id: i32,
}

struct Wrapper {
    datas: Vec<Data>,
}

impl Wrapper{
    fn insert_after(&mut self, id: i32, new_data: Data) {
        let mut index = None;
        for (i, data) in self.datas.iter().enumerate() {
            if data.id == id {
                index = Some(i);
                break;
            }
        }
        if let Some(index) = index {
            self.datas.insert(index, new_data);
        }
    }
}

Is there a way to achieve the same functionality as insert_after using only iterators and no for loop? Is there a way to remove the additional if statement, and the optional index variable?

1 Answers

Yes, iterators have a position method that lets you find the index of an element that matches a predicate:

fn insert_after(&mut self, id: i32, new_data: Data) {
    if let Some(index) = self.datas.iter().position(|x| x.id == id) {
        self.datas.insert(index, new_data);
    }
}

I cannot think of a more readable way to express this, although if you really wanted to get rid of the if let you could probably use Option::map:

fn insert_after(&mut self, id: i32, new_data: Data) {
    self.datas.iter().position(|x| x.id == id).map(|index| {
        self.datas.insert(index, new_data);
    });
}

Although this is arguably less readable.

Related