Look into reservoir sampling: https://en.m.wikipedia.org/wiki/Reservoir_sampling Answer from hippyup on reddit.com
🌐
Reddit
reddit.com › r/rust › what's the best way to shuffle an iterator?
r/rust on Reddit: What's the best way to shuffle an iterator?
April 7, 2023 -

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.

🌐
Rust Programming Language
users.rust-lang.org › help
[Solved] Efficient rust random shuffle of? - help - The Rust Programming Language Forum
February 20, 2019 - - Stack Overflow extern crate rand; use rand::{thread_rng, Rng}; fn main() { let mut vec: Vec = (0..10).collect(); let slice: &mut [u32] = &mut vec; thread_rng().shuffle(slice); } My question is: I'm doing this on a Vec with 300_000_000 entries.
Discussions

Shuffle Iterator
Background What is your motivation? In a game AI, I'd like to use a random permutation of a vector. However, the order is only used in an iterator and discarded afterwards. Feature request I... More on github.com
🌐 github.com
5
June 17, 2019
Shuffling object vectors around
I guess this is a trivial one but I have no idea how to make it work. So I wanna save space and thus not make any extra copies of anything if I do not need to. I wanna switch the content of two vectors in my object through a private method. The example below i am showing is an oversimplification ... More on users.rust-lang.org
🌐 users.rust-lang.org
1
0
February 18, 2020
Appropriate name for single vector shuffle
Shuffles for single vectors are currently called permute! (when the indices are compile-time constants) and permute_dyn (when the indices are provided with a run-time vector of the same vector size). These shuffles are allowed to repeat ... More on github.com
🌐 github.com
4
August 29, 2018
java - How to iterate over an enum, insert it into a vector, then shuffle it in Rust? - Stack Overflow
I'm writing code to initialize a deck with 52 cards and shuffle them. In Java, I use an ArrayList and iterate through the Suit enum and the Rank enum, adding a Card(suit,rank) object as I go along. I then use Collections.shuffle(). I am trying to port this code to Rust, using vectors and structs. More on stackoverflow.com
🌐 stackoverflow.com
September 10, 2019
Top answer
1 of 3
133

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.


2 of 3
20

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);
}
🌐
Programming Idioms
programming-idioms.org › idiom › 10 › shuffle-a-list › 410 › rust
Shuffle a list, in Rust
Rust · use std::hash::{BuildHasher, Hasher, RandomState}; pub fn shuffle<T>(vec: &mut [T]) { let n = vec.len(); for i in 0..(n - 1) { let j = rand() % (n - i) + i; vec.swap(i, j); } } pub fn rand() -> usize { RandomState::new().build_hasher().finish() as usize } C · Clojure · C++ C# C# D · Dart · Dart · Elixir · Erlang · Fortran · Go · Go · Go · Go · Go · Groovy · Haskell · JS · Java ·
🌐
Rust
docs.rs › shuffle › latest › shuffle
shuffle - Rust
use shuffle::shuffler::Shuffler; use shuffle::irs::Irs; use rand::rngs::mock::StepRng; let mut rng = StepRng::new(2, 13); let mut irs = Irs::default(); let mut input = vec![1, 2, 3, 4, 5]; irs.shuffle(&mut input, &mut rng); assert_eq!(&input, &[4, 1, 5, 3, 2]);
🌐
GitHub
github.com › rust-random › rand › issues › 826
Shuffle Iterator · Issue #826 · rust-random/rand
June 17, 2019 - Background What is your motivation? In a game AI, I'd like to use a random permutation of a vector. However, the order is only used in an iterator and discarded afterwards. Feature request I'd like to have a struct RandomizedOrder tha...
Author   ThomasdenH
🌐
Rust
docs.rs › shuffle
Crate shuffle - Rust
use shuffle::shuffler::Shuffler; use shuffle::irs::Irs; use rand::rngs::mock::StepRng; let mut rng = StepRng::new(2, 13); let mut irs = Irs::default(); let mut input = vec![1, 2, 3, 4, 5]; irs.shuffle(&mut input, &mut rng); assert_eq!(&input, &[4, 1, 5, 3, 2]);
Find elsewhere
🌐
crates.io
crates.io › crates › shuffle
shuffle - crates.io: Rust Package Registry
Implementation of various shuffling algorithms over slices.
🌐
Rust
docs.rs › nois › latest › nois › fn.shuffle.html
shuffle in nois - Rust
use nois::{randomness_from_str, shuffle}; let randomness = randomness_from_str("9e8e26615f51552aa3b18b6f0bcf0dae5afbe30321e8d7ea7fa51ebeb1d8fe62").unwrap(); let original = vec![ "bob".to_string(), "mary".to_string(), "su".to_string(), "marc".to_string() ]; let shuffled = shuffle(randomness, original.clone()); // The length of the vector is the same but the order of the elements has changed assert_eq!(shuffled.len(), original.len()); assert_ne!(shuffled, original);
🌐
The Rust Programming Language
rust-lang.github.io › packed_simd › packed_simd_2 › macro.shuffle.html
shuffle in packed_simd_2 - Rust
... // Shuffle allows reordering the elements: let x = i32x4::new(1, 2, 3, 4); let y = i32x4::new(5, 6, 7, 8); let r = shuffle!(x, y, [4, 0, 5, 1]); assert_eq!(r, i32x4::new(5, 1, 6, 2)); // The resulting vector can als be smaller than the input: let r = shuffle!(x, y, [1, 6]); assert_eq!(r, ...
🌐
The Rust Programming Language
rust-lang.github.io › packed_simd › src › packed_simd_2 › api › shuffle.rs.html
shuffle.rs - source
/// # } /// ``` #[macro_export] macro_rules! shuffle { ($vec0:expr, $vec1:expr, [$l0:expr, $l1:expr]) => {{ #[allow(unused_unsafe)] unsafe { $crate::Simd($crate::__shuffle_vector2::<{[$l0, $l1]}, _, _>( $vec0.0, $vec1.0, )) } }}; ($vec0:expr, $vec1:expr, [$l0:expr, $l1:expr, $l2:expr, $l3:expr]) => {{ #[allow(unused_unsafe)] unsafe { $crate::Simd($crate::__shuffle_vector4::<{[$l0, $l1, $l2, $l3]}, _, _>( $vec0.0, $vec1.0, )) } }}; ($vec0:expr, $vec1:expr, [$l0:expr, $l1:expr, $l2:expr, $l3:expr, $l4:expr, $l5:expr, $l6:expr, $l7:expr]) => {{ #[allow(unused_unsafe)] unsafe { $crate::Simd($crate
🌐
Rust Rand
rust-random.github.io › book › guide-seq.html
Sequences - The Rust Rand Book
SliceRandom::partial_shuffle: partial shuffle; useful to extract amount random elements in random order
🌐
GitHub
github.com › rust-lang-nursery › packed_simd › issues › 102
Appropriate name for single vector shuffle · Issue #102 · rust-lang/packed_simd
August 29, 2018 - Shuffles for single vectors are currently called permute! (when the indices are compile-time constants) and permute_dyn (when the indices are provided with a run-time vector of the same vector size). These shuffles are allowed to repeat ...
Author   gnzlbg
🌐
Rust Programming Language
users.rust-lang.org › t › how-can-i-using-stable-rust-mutably-iterate-over-a-random-shuffle › 105457
How can I, using stable rust, mutably iterate over a random shuffle? - The Rust Programming Language Forum
January 17, 2024 - This is a follow up to a previous question. I ended up taking the previous solution and updating it to use Rayon for parallel computation. The code now looks like this all_orgs.par_chunks_mut(48).for_each(|chunk: &mut [Organism]|{ for i in 0 .. chunk.len() { let (left, others) = chunk.split_at_mut(i); let (middle, right) = others.split_at_mut(1); let org1 = &mut middle[0]; //process left for org2 in left { single_match_up(org1, org2); ...
Top answer
1 of 3
7

As of Rust 1.48, VecDeque supports the make_contiguous() method. That method doesn't allocate and has complexity of O(n), like shuffling itself. Therefore you can shuffle a VecDeque by calling make_contiguous() and then shuffling the returned slice:

use rand::prelude::*;
use std::collections::VecDeque;

pub fn shuffle<T>(v: &mut VecDeque<T>, rng: &mut impl Rng) {
    v.make_contiguous().shuffle(rng);
}

Playground

Historical answer follows below.


Unfortunately, the rand::Rng::shuffle method is defined to shuffle slices. Due to its own complexity constraints a VecDeque cannot store its elements in a slice, so shuffle can never be directly invoked on a VecDeque.

The real requirement of the values argument to shuffle algorithm are finite sequence length, O(1) element access, and the ability to swap elements, all of which VecDeque fulfills. It would be nice if there were a trait that incorporates these, so that values could be generic on that, but there isn't one.

With the current library, you have two options:

  • Use Vec::from(deque) to copy the VecDeque into a temporary Vec, shuffle the vector, and return the contents back to VecDeque. The complexity of the operation will remain O(n), but it will require a potentially large and costly heap allocation of the temporary vector.

  • Implement the shuffle on VecDeque yourself. The Fisher-Yates shuffle used by rand::Rng is well understood and easy to implement. While in theory the standard library could switch to a different shuffle algorithm, that is not likely to happen in practice.

A generic form of the second option, using a trait to express the len-and-swap requirement, and taking the code of rand::Rng::shuffle, could look like this:

use std::collections::VecDeque;

// Real requirement for shuffle
trait LenAndSwap {
    fn len(&self) -> usize;
    fn swap(&mut self, i: usize, j: usize);
}

// A copy of an earlier version of rand::Rng::shuffle, with the signature
// modified to accept any type that implements LenAndSwap
fn shuffle(values: &mut impl LenAndSwap, rng: &mut impl rand::Rng) {
    let mut i = values.len();
    while i >= 2 {
        // invariant: elements with index >= i have been locked in place.
        i -= 1;
        // lock element i in place.
        values.swap(i, rng.gen_range(0..=i));
    }
}

// VecDeque trivially fulfills the LenAndSwap requirement, but
// we have to spell it out.
impl<T> LenAndSwap for VecDeque<T> {
    fn len(&self) -> usize {
        self.len()
    }
    fn swap(&mut self, i: usize, j: usize) {
        self.swap(i, j)
    }
}

fn main() {
    let mut v: VecDeque<u64> = [1, 2, 3, 4].into_iter().collect();
    shuffle(&mut v, &mut rand::thread_rng());
    println!("{:?}", v);
}
2 of 3
2

You can use make_contiguous (documentation) to create a mutable slice that you can then shuffle:

use rand::prelude::*;
use std::collections::VecDeque;

fn main() {
    let mut deque = VecDeque::new();
    for p in 0..10 {
        deque.push_back(p);
    }
    deque.make_contiguous().shuffle(&mut rand::thread_rng());
    println!("Random deque: {:?}", deque)
}

Playground Link if you want to try it out online.

🌐
Javaer101
javaer101.com › en › article › 12217283.html
How do I create a Vec from a range and shuffle it? - Javaer101
October 21, 2020 - 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); }