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);
}
What's the best way to shuffle an iterator?
Shuffle Iterator
Shuffling object vectors around
How can I, using stable rust, mutably iterate over a random shuffle?
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.
Correct me if I'm wrong: you're looking for a way to retain n random elements in a Vec and discard the rest. In that case, the easiest way would be to use partial_shuffle(), a rand function implemented for slices.
Shuffle a slice in place, but exit early.
Returns two mutable slices from the source slice. The first contains amount elements randomly permuted. The second has the remaining elements that are not fully shuffled.
use rand::{thread_rng, seq::SliceRandom};
fn main() {
let mut rng = thread_rng();
// Use the `RangeInclusive` (`..=`) syntax at times like this.
for n in 1..=10 {
let mut elements: Vec<u8> = (1..=10).collect();
let (elements, _rest) = elements.as_mut_slice().partial_shuffle(&mut rng, n);
println!("{n}: {elements:?}");
}
}
Run this snippet on Rust Playground.
elements is shadowed, going from a Vec to a &mut [T]. If you're only going to use it inside the function, that's probably all you'll need. However, since it's a reference, you can't return it; the data it's pointing to is owned by the original vector, which will be dropped when it goes out of scope. If that's what you need, you'll have to turn the slice into a Vec.
While you can simply construct a new one from it using Vec::from, I suspect (but haven't tested) that it's more efficient to use Vec::split_off.
Splits the collection into two at the given index.
Returns a newly allocated vector containing the elements in the range [at, len). After the call, the original vector will be left containing the elements [0, at) with its previous capacity unchanged.
use rand::{thread_rng, seq::SliceRandom};
fn main() {
let mut rng = thread_rng();
for n in 1..=10 {
let mut elements: Vec<u8> = (1..=10).collect();
elements.as_mut_slice().partial_shuffle(&mut rng, n);
let elements = elements.split_off(elements.len() - n);
// `elements` is still a `Vec`; this time, containing only
// the shuffled elements. You can use it as the return value.
println!("{n}: {elements:?}");
}
}
Run this snippet on Rust Playground.
Since this function lives on a performance-critical path, I'd recommend benchmarking it against your current implementation. At the time of writing this, criterion is the most popular way to do that. That said, rand is an established library, so I imagine it will perform as well or better than a manual implementation.
Sample Benchmark
I don't know what kind of numbers you're working with, but here's a sample benchmark with for n in 1..=100 and (1..=100).collect() (i.e. 100 instead of 10 in both places) without the print statements:
manual time: [73.683 µs 73.749 µs 73.821 µs]
rand with slice time: [68.074 µs 68.147 µs 68.226 µs]
rand with vec time: [54.147 µs 54.213 µs 54.288 µs]
Bizarrely, splitting off a Vec performed vastly better than not. Unless I made an error in my benchmarks, the compiler is probably doing something under the hood that you'll need a more experienced Rustacean than me to explain.
Benchmark Implementation
Cargo.toml
[dependencies]
rand = "0.8.5"
[dev-dependencies]
criterion = "0.4.0"
[[bench]]
name = "rand_benchmark"
harness = false
[[bench]]
name = "rand_vec_benchmark"
harness = false
[[bench]]
name = "manual_benchmark"
harness = false
benches/manual_benchmark.rs
use criterion::{criterion_group, criterion_main, Criterion};
fn manual_solution() {
for n in 1..=100 {
let mut elements: Vec<u8> = (1..=100).collect();
keep_n_rand(&mut elements, n);
}
}
fn keep_n_rand<T>(elements: &mut Vec<T>, n: usize) {
use rand::{thread_rng, Rng};
let mut rng = thread_rng();
for i in n..elements.len() {
let j = rng.gen_range(0..i);
if j < n {
elements.swap(i, j);
}
}
elements.truncate(n);
}
fn benchmark(c: &mut Criterion) {
c.bench_function("manual", |b| b.iter(manual_solution));
}
criterion_group!(benches, benchmark);
criterion_main!(benches);
benches/rand_benchmark.rs
use criterion::{criterion_group, criterion_main, Criterion};
fn rand_solution() {
use rand::{seq::SliceRandom, thread_rng};
let mut rng = thread_rng();
for n in 1..=100 {
let mut elements: Vec<u8> = (1..=100).collect();
let (_elements, _) = elements.as_mut_slice().partial_shuffle(&mut rng, n);
}
}
fn benchmark(c: &mut Criterion) {
c.bench_function("rand with slice", |b| b.iter(rand_solution));
}
criterion_group!(benches, benchmark);
criterion_main!(benches);
benches/rand_vec_benchmark.rs
use criterion::{criterion_group, criterion_main, Criterion};
fn rand_solution() {
use rand::{seq::SliceRandom, thread_rng};
let mut rng = thread_rng();
for n in 1..=100 {
let mut elements: Vec<u8> = (1..=100).collect();
elements.as_mut_slice().partial_shuffle(&mut rng, n);
let _elements = elements.split_off(elements.len() - n);
}
}
fn benchmark(c: &mut Criterion) {
c.bench_function("rand with vec", |b| b.iter(rand_solution));
}
criterion_group!(benches, benchmark);
criterion_main!(benches);
Is that possible and desirable in rust?
It is not possible unless you constrain T: Copy or T: Clone: while C++ uses non-destructive moves (the source is in a valid but unspecified state) Rust uses destructive moves (the source is gone).
There are ways around it using unsafe but they require being very careful and it's probably not worth the hassle (you can look at Vec::swap_remove for a taste, it basically does what you're doing here except only between j and the last element of the vec).
I'd also recommend verified_tinker's solution, as I'm not convinced your shuffle is unbiased.