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,
VecDeque
supports themake_contiguous()
method. That method doesn't allocate and has complexity of O(n), like shuffling itself. Therefore you can shuffle aVecDeque
by callingmake_contiguous()
and then shuffling the returned slice:Playground
Historical answer follows below.
Unfortunately, the
rand::Rng::shuffle
method is defined to shuffle slices. Due to its own complexity constraints aVecDeque
cannot store its elements in a slice, soshuffle
can never be directly invoked on aVecDeque
.The real requirement of the
values
argument toshuffle
algorithm are finite sequence length, O(1) element access, and the ability to swap elements, all of whichVecDeque
fulfills. It would be nice if there were a trait that incorporates these, so thatvalues
could be generic on that, but there isn't one.With the current library, you have two options:
Use
Vec::from(deque)
to copy theVecDeque
into 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
VecDeque
yourself. The Fisher-Yates shuffle used byrand::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: