3

I've got a vector:

let v = Vec<T>::with_capacity(10);

I want to populate it with data, in reverse order:

let i = 10;
while i > 0 {
    i -= 1;
    v[i] = non_pure_function(i);
}

Unfortunately, this panics; when allocating with Vec::with_capacity, the actual initial length of the vector is still 0.

How can I best accomplish this? What if I have no constructor for T?

wizzwizz4
  • 6,140
  • 2
  • 26
  • 62
  • 1
    [This one](https://stackoverflow.com/q/37152766/1233251) seems relevant, but the answers might not be very appealing. – E_net4 Jun 27 '19 at 08:45
  • You may initalize vec like this `[0; 10].to_vec()` – Ömer Erden Jun 27 '19 at 08:48
  • @ÖmerErden It's not `{integer}`s, though, and I don't have access to the constructor. – wizzwizz4 Jun 27 '19 at 08:49
  • 1
    @E_net4theAbusedDownvoter Once again, you've found the duplicate target. – wizzwizz4 Jun 27 '19 at 08:49
  • 1
    It would be nice to have something like `reverse_collect`. – starblue Jun 27 '19 at 09:13
  • @starblue It's theoretically possible to create such a thing with `unsafe`, though I'm nowhere near clever enough at Rust to do so. – wizzwizz4 Jun 27 '19 at 09:15
  • @wizzwizz4 The point is that somebody clever enough could write it using `unsafe`, then everybody could use it safely. Though I'm not sure this use case is common enough to put it in the standard library. – starblue Jun 28 '19 at 07:15

1 Answers1

2

How can I Populate a vector in reverse?

You can do it with VecDeque:

use std::collections::VecDeque;

fn main() {
    let mut v = VecDeque::new();

    for i in 0..5 {
        v.push_front(i);
    }

    for item in v {
        print!("{}", item);
    }
}

Playground


Instead of using VecDeque you can solve this problem with using array and the iterator:

  • Declare an array containing Option types.
  • Set array cells with the indexes.
  • Iterate over your array.
  • Filter your array to eliminate None values
  • Map the unwrapped values
  • Collect them into vector.
fn main() {
    let mut v = [None; 10];
    let mut i = 5i32;

    while i > 0 {
        i -= 1;
        v[i as usize] = Some(4i32 - i);
    }

    let reverse_populated: Vec<i32> = v
        .iter()
        .filter(|x| x.is_some())
        .map(|x| x.unwrap())
        .collect();

    for item in reverse_populated {
        print!("{:?}", item);
    }
}

Playground


Both output will be: 43210

Community
  • 1
  • 1
Akiner Alkan
  • 6,145
  • 3
  • 32
  • 68
  • But then I'd have to convert that to a `Vec`. – wizzwizz4 Jun 27 '19 at 08:49
  • Since Vec implements From trait for VecDeque, you can easily convert it to vec. – Akiner Alkan Jun 27 '19 at 08:55
  • 1
    But if I'm doing this, couldn't I just populate the vector forwards and then reverse it? Why would this, which requires more memory allocations, be better? – wizzwizz4 Jun 27 '19 at 08:57
  • Converting `VecDeque` to `Vec` will not cause any new allocations. Both of them hold internally `RawVec` and this buffer is passed from one to another. Depending on the current state of `VecDeque` the elements may need to be reordered, which is done by few calls to `ptr::copy`. That is probably faster than reversing order of elements (few big memcpy, vs multiple smallers ones). But of course writing the elements straight to their final position would be best. – michalsrb Jun 27 '19 at 12:38