Search code examples
rustclosures

Is it possible to apply a function using `.map()` to every element of a nested vector in Rust?


Is it possible to apply a closure or function to every element of a Vec<Vec<T>> ?

Can this be done with .map()? If not, then is there an alternative?

I want to convert a Vec<Vec<Option<f64>>> to a Vec<Vec<f64>>. My first thoughts on how to do this are to use .map() plus a closure.

When I attempted this, I found that .iter().map(f) was not the right way, as this applied f to every element of the first Vec, and those elements are themselves Vecs.

I also investigated iter().flatten() but this produces a Vec<T> containing all the elements from Vec<Vec<T>> which "destroys" the 2-dimensional structure, which I need to keep.

I guess one possible way would be to make the closure logic of f to be something which itself calls iter().map(g), where g does the desired conversion from Option<f64> -> f64. But this is perhaps a bit inelegant.


Solution

  • Yes, it's possible:

    fn main() {
        let vec = vec![vec![Some(1.), None, Some(2.)]];
    
        let vec2 = vec.iter().map(|inner_vec| {
            inner_vec.iter().map(|option| {
                option.unwrap_or(0.)
            }).collect::<Vec<_>>()
        }).collect::<Vec<_>>();
    
        println!("vec2: {:?}", vec2);
    }
    
    // Program output:
    // vec2: [[1.0, 0.0, 2.0]]
    

    Basically, you can iterate over the outermost Vec and map its elements. These elements are inner vecs that you can (again) iterate over and map its elements. You can then apply some operation to the inner Option<f64> such as .unwrap_or(0.) and then re-collect both levels of nesting back into Vecs again.