残念ながら、rand::Rng::shuffle
methodは、スライスをシャッフルするように定義されています。独自の複雑さの制約のため、VecDeque
はスライスにその要素を格納できないため、VecDeque
でshuffle
を直接呼び出すことはできません。
shuffle
アルゴリズムへの引数values
の実際の要件は、有限のシーケンス長、O(1)要素アクセス、および要素をスワップする能力です(すべてVecDeque
)。これらを組み込んだ形質があるといいでしょう。つまり、values
は一般的なものですが、そうではありません。
使用Vec::from(deque)
は、一時的Vec
にVecDeque
をコピーベクトルをシャッフルし、VecDeque
に戻って内容を返すために:現在のライブラリと
は、次の2つのオプションがあります。この操作の複雑さはO(n)のままですが、一時的なベクトルの潜在的に大規模で高価なヒープ割り当てが必要になります。
自分でVecDeque
にシャッフルを実装します。 によって使用されるFisher-Yates shuffleは、よく理解され、実装が容易であり、現代的な形態では、それは約5 lines of codeまでしか沸騰しない。理論的には標準ライブラリは異なるシャッフルアルゴリズムに切り替えることができますが、それは実際には起こりそうにありません。
第二のオプションの一般的な形態は、このようになり、LENアンドスワップ要件を発現するように形質を用いて、及びrand::Rng::shuffle
のコードを取る:
extern crate rand;
use std::collections::VecDeque;
// Real requirement for shuffle
trait LenAndSwap {
fn len(&self) -> usize;
fn swap(&mut self, i: usize, j: usize);
}
// An exact copy of rand::Rng::shuffle, with the signature modified to
// accept any type that implements LenAndSwap
fn shuffle<T, R>(values: &mut T, mut rng: R)
where T: LenAndSwap,
R: 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 + 1));
}
}
// 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].iter().cloned().collect();
shuffle(&mut v, rand::thread_rng());
println!("{:?}", v);
}
この非常に長く詳細な説明をありがとう! –
確かに、「シャッフル」の議論は、連続性が未使用であることを見ると非常に残念です。 @MatthieuM。 –
たぶん 'shuffle'はスライスに定義されるべきではないでしょうが、' Shufflable'特性(既定ではスライスに定義されています)は上記の 'LenAndSwap'と同じ方法で定義されていますか?これは現在の定義と下位互換性があります。 – user4815162342