Rand v0.6.0
The Rng::shuffle method is now deprecated; rand::seq::SliceRandom trait should be used. It provides the shuffle() method on all slices, which accepts an Rng instance:
// Rust edition 2018 no longer needs extern crate
use rand::thread_rng;
use rand::seq::SliceRandom;
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
vec.shuffle(&mut thread_rng());
println!("{:?}", vec);
}
See it on Playground.
Original answer
You're very close. This should work:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
let slice: &mut [u32] = &mut vec;
thread_rng().shuffle(slice);
}
&mut [T] is implicitly coercible to &[T], and you annotated the slice variable with &[u32], so the slice became immutable: &mut [u32] was coerced to &[u32]. mut on the variable is not relevant here because slices are just borrows into data owned by someone else, so they do not have inherited mutability - their mutability is encoded in their types.
In fact, you don't need an annotation on slice at all. This works as well:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
let slice = vec.as_mut_slice();
thread_rng().shuffle(slice);
}
You don't even need the intermediate variable:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
thread_rng().shuffle(&mut vec);
}
You should read The Rust Programming Language as it explains the concepts of ownership and borrowing and how they interact with mutability.
Answer from Vladimir Matveev on Stack Overflow
Rand v0.6.0
The Rng::shuffle method is now deprecated; rand::seq::SliceRandom trait should be used. It provides the shuffle() method on all slices, which accepts an Rng instance:
// Rust edition 2018 no longer needs extern crate
use rand::thread_rng;
use rand::seq::SliceRandom;
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
vec.shuffle(&mut thread_rng());
println!("{:?}", vec);
}
See it on Playground.
Original answer
You're very close. This should work:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
let slice: &mut [u32] = &mut vec;
thread_rng().shuffle(slice);
}
&mut [T] is implicitly coercible to &[T], and you annotated the slice variable with &[u32], so the slice became immutable: &mut [u32] was coerced to &[u32]. mut on the variable is not relevant here because slices are just borrows into data owned by someone else, so they do not have inherited mutability - their mutability is encoded in their types.
In fact, you don't need an annotation on slice at all. This works as well:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
let slice = vec.as_mut_slice();
thread_rng().shuffle(slice);
}
You don't even need the intermediate variable:
extern crate rand;
use rand::{thread_rng, Rng};
fn main() {
let mut vec: Vec<u32> = (0..10).collect();
thread_rng().shuffle(&mut vec);
}
You should read The Rust Programming Language as it explains the concepts of ownership and borrowing and how they interact with mutability.
You can use shuffle like this:
extern crate rand;
use rand::Rng;
fn main() {
let mut vec: Vec<usize> = (0..10).collect();
println!("{:?}", vec);
rand::thread_rng().shuffle(&mut vec);
println!("{:?}", vec);
}
I need to get some random distinct elements inside a range. I don't need to shuffle all the items, so collecting the iterator into a `vec` and calling the ` shuffle` method on it is not desirable. Is there a way to iterate over the range in random order and only get the first `n` items?
EDIT with some context:
I have arbitrarily large collections of `BigInt` numbers and I need to retrieve `n` values in a range from `0` to numbers even of hundreds or thousands of bits. I cannot collect 1 googol items in a `Vec` only to retrieve some tenths or hundreds values. Of course, I could assume that the probability of getting the same number twice is negligible in this specific case but, since the range is arbitrary large I could also have a range of 10 numbers and I must take 9 of them. As a general solution I have started getting random numbers in the target range and manually check if this has been already taken in a previous iteration but I was looking for a lazy solution that could avoid unnecessary checks or allocations.