How do I generate a vector of 100 64-bit integer values in the range from 1 to 20, allowing duplicates?
-
1Generate one and keep on going. /halfserious – Veedrac Jan 12 '18 at 02:04
-
Like ' let secret_number = rand::thread_rng().gen_range(1, 101);'? I could make a closure out of it and map it to a vector for 1..100? – mrsteve Jan 12 '18 at 02:22
-
Yeah, pretty much. – Veedrac Jan 12 '18 at 02:24
2 Answers
There are a few main pieces that you need here. First, how to create a vector of 100 calculated items? The easiest way is to create a range of 100 and map over those items. For instance you could do:
let vals: Vec<u64> = (0..100).map(|v| v + 1000).collect();
// [1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, ...
Splitting this up:
0..100
creates an iterator for 0 through 99.map
processes each item in the iterator when the iterator is processed..collect()
takes an iterator and converts it into any type that implementsFromIterator
which in your case isVec
.
Expanding on this for your random values, you can adjust the .map
function to generate a random value from 0 to 20 using the rand
crate's gen_range
function to create a numeric value within a given range.
use rand::Rng; // 0.6.5
fn main() {
let mut rng = rand::thread_rng();
let vals: Vec<u64> = (0..100).map(|_| rng.gen_range(0, 20)).collect();
println!("{:?}", vals);
}
You should also consider using the rand::distributions::Uniform
type to create the range up front, which is is more efficient than calling gen_range
multiple times, then pull samples from it 100 times:
use rand::{distributions::Uniform, Rng}; // 0.6.5
fn main() {
let mut rng = rand::thread_rng();
let range = Uniform::new(0, 20);
let vals: Vec<u64> = (0..100).map(|_| rng.sample(&range)).collect();
println!("{:?}", vals);
}

- 388,571
- 95
- 1,107
- 1,366

- 156,129
- 30
- 331
- 251
TL;DR:
use rand::{distributions::Uniform, Rng}; // 0.8.0
fn main() {
let range = Uniform::from(0..20);
let values: Vec<u64> = rand::thread_rng().sample_iter(&range).take(100).collect();
println!("{:?}", values);
}
It's important to use rand::distributions::uniform::Uniform
instead of simply performing the modulo of a uniform random number. See Why do people say there is modulo bias when using a random number generator? for more details.
Since we are generating multiple numbers from a range, it's more performant to create the Uniform
once and reuse it. Creating the Uniform
does some computation to avoid sampling bias.
We can use Rng::sample_iter
to create an iterator of random values and then take
some number of them, collecting into a Vec
. collect
will even make use of Iterator::size_hint
to allocate exactly the right number of elements.
If you only needed a single random number in the range, you could use the shortcut Rng::gen_range
:
use rand::Rng; // 0.8.0
fn main() {
let mut rng = rand::thread_rng();
let value: u64 = rng.gen_range(0..20);
}
If you needed a vector of random values without limiting to a range, you can use the Standard
distribution:
use rand::{distributions::Standard, Rng}; // 0.8.0
fn main() {
let values: Vec<u64> = rand::thread_rng().sample_iter(Standard).take(100).collect();
println!("{:?}", values);
}

- 388,571
- 95
- 1,107
- 1,366
-
Could be `rng.gen_iter::
().take(100).map(|n| n % 20 + 1).collect();` with only std. – Stargateur Jan 12 '18 at 09:52 -
1@Stargateur You might at least note that `% 20` is not the same as `gen_range(0, 20)` - and I'd really advise against "cheating" on this level, even if for specific use cases it might not matter. – Stefan Jan 12 '18 at 10:12
-
@Stefan What do you mean, I'm not cheating, this is how all ranges are implemented, https://doc.rust-lang.org/rand/src/rand/distributions/range.rs.html#127. This is very classic. – Stargateur Jan 12 '18 at 10:30
-
@Stargateur Just read the comment and the `accept_zone` condition above the line you just linked to see the difference. – Stefan Jan 12 '18 at 10:35
-
2The `accept_zone` calculation is the reason why you should allocate [`Range`](https://doc.rust-lang.org/rand/rand/distributions/range/struct.Range.html) once and reuse it, instead of calling [`gen_range`](https://doc.rust-lang.org/rand/rand/trait.Rng.html#method.gen_range) in a loop. – Stefan Jan 12 '18 at 10:39