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..100creates an iterator for 0 through 99
- .mapprocesses each item in the iterator when the iterator is processed.
- .collect()takes an iterator and converts it into any type that implements- FromIteratorwhich in your case is- Vec.
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
