16

How do I initialize a vector from 0 to n in Rust? Is there another way of doing that than creating an empty vector and invoking push inside a loop?

I prefer a one-liner.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Thorkil Værge
  • 2,727
  • 5
  • 32
  • 48

2 Answers2

19

A range can be collected into a vector:

pub fn sequence(n: u32) -> Vec<u32> {
    (0..n).collect()
}

Playground

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
  • 8
    Nicer (IMO): `Vec::from_iter(0..n)` – Chayim Friedman Dec 16 '21 at 22:37
  • Both solutions are nice and save me three lines of code :) I'll have to think a bit about which one I prefer... – Thorkil Værge Dec 16 '21 at 22:38
  • 2
    I think you'll see `collect()` used more often than `from_iter()` because it can just be tacked on existing iterator chains, but functionally they do the same thing. – kmdreko Dec 16 '21 at 22:46
  • 1
    @kmdreko There is actually a difference: `collect()` needs an `Iterator`, while `FromIterator::from_iter()` takes an `IntoIterator`. Ranges are `Iterator`s thus it doesn't matter, but for arrays, for example, it's `[1, 2, 3].into_iter().collect::>()` vs. `Vec::from_iter([1, 2, 3])` which is a bigger difference. – Chayim Friedman Dec 17 '21 at 00:47
  • 5
    @kmdreko And since `FromIterator` is in the prelude since edition 2021, I'd expect much more usages of it (I use it more now, and I also saw that in other people's code). It's just shorter when you don't perform any transformation on the iterable, just converting to to another container: `Container::from_iter(v)` instead of `v.into_iter().collect::()`. – Chayim Friedman Dec 17 '21 at 00:50
5

Here is how you can do it as a one-liner:

let n = 4;

let v: Vec<i32> = (0..n).collect();  // the last element will be n-1
assert_eq!(v, vec![0, 1, 2, 3]);

let v: Vec<i32> = (0..=n).collect();  // the last element will be n
assert_eq!(v, vec![0, 1, 2, 3, 4]);

Or, alternatively:

let v: Vec<i32> = Vec::from_iter(0..n);  // the last element will be n-1
assert_eq!(v, vec![0, 1, 2, 3]);

let v: Vec<i32> = Vec::from_iter(0..=n);  // the last element will be n
assert_eq!(v, vec![0, 1, 2, 3, 4]);

Instead of i32 we could use other numeric types like u8, u16, i8, etc. That's because both collect() and Vec::from_iter are generic methods.

All those solutions make use of the Range or RangeInclusive structs respectively, both of which implement Iterator. That allows them to easily be converted into a Vec, which is most often done via the collect() method.

at54321
  • 8,726
  • 26
  • 46