Search code examples
rustiteratordeclarative

How do I avoid allocations in Iterator::flat_map?


I have a Vec of integers and I want to create a new Vec which contains those integers and squares of those integers. I could do this imperatively:

let v = vec![1, 2, 3];
let mut new_v = Vec::new(); // new instead of with_capacity for simplicity sake.
for &x in v.iter() {
    new_v.push(x);
    new_v.push(x * x);
}
println!("{:?}", new_v);

but I want to use iterators. I came up with this code:

let v = vec![1, 2, 3];
let new_v: Vec<_> = v.iter()
    .flat_map(|&x| vec![x, x * x])
    .collect();
println!("{:?}", new_v);

but it allocates an intermediate Vec in the flat_map function.

How to use flat_map without allocations?


Solution

  • You can use an ArrayVec for this.

    let v = vec![1, 2, 3];
    let new_v: Vec<_> = v.iter()
        .flat_map(|&x| ArrayVec::from([x, x * x]))
        .collect();
    

    Making arrays be by-value iterators, so that you wouldn't need ArrayVec has been discussed, see https://github.com/rust-lang/rust/issues/25725 and the linked PRs.