I can shuffle a regular vector quite simply like this:
extern crate rand;
use rand::Rng;
fn shuffle(coll: &mut Vec<i32>) {
rand::thread_rng().shuffle(coll);
}
The problem is, my code now requires the use of a std::collections::VecDeque instead, which causes this code to not compile.
What's the simplest way of getting around this?
As of Rust 1.48,
VecDequesupports themake_contiguous()method. That method doesn't allocate and has complexity of O(n), like shuffling itself. Therefore you can shuffle aVecDequeby callingmake_contiguous()and then shuffling the returned slice:Playground
Historical answer follows below.
Unfortunately, the
rand::Rng::shufflemethod is defined to shuffle slices. Due to its own complexity constraints aVecDequecannot store its elements in a slice, soshufflecan never be directly invoked on aVecDeque.The real requirement of the
valuesargument toshufflealgorithm are finite sequence length, O(1) element access, and the ability to swap elements, all of whichVecDequefulfills. It would be nice if there were a trait that incorporates these, so thatvaluescould be generic on that, but there isn't one.With the current library, you have two options:
Use
Vec::from(deque)to copy theVecDequeinto a temporaryVec, shuffle the vector, and return the contents back toVecDeque. 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
VecDequeyourself. The Fisher-Yates shuffle used byrand::Rngis 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: