シャッフルの問題があります。カードのスタックのように、値の配列を完全にシャッフルすることについては、多くのページと議論があります。
私が必要としているのは、配列要素を開始位置から最大で N の場所に一様に移動させるシャッフルです。
つまり、N が 2 の場合、要素 I は最大でも I-2 から I+2 (配列の境界内) の位置にシャッフルされます。
これは、いくつかの単純なソリューションでは扱いにくいことが証明されており、要素の動きに方向性バイアスが生じたり、量が不均一になったりします。
シャッフルの問題があります。カードのスタックのように、値の配列を完全にシャッフルすることについては、多くのページと議論があります。
私が必要としているのは、配列要素を開始位置から最大で N の場所に一様に移動させるシャッフルです。
つまり、N が 2 の場合、要素 I は最大でも I-2 から I+2 (配列の境界内) の位置にシャッフルされます。
これは、いくつかの単純なソリューションでは扱いにくいことが証明されており、要素の動きに方向性バイアスが生じたり、量が不均一になったりします。
そうです、これはトリッキーです!まず、人為的に非ランダムな結果を作成しないようにするために、さらにいくつかのルールを確立する必要があります。
これで、実際に問題を解決できます。
i + [-N, N]
でランダム値の配列を生成します。i
配列の範囲外の値を正規化します (例: -1
should becomelength-1
およびlength
should be 0
)。[3, 1, 1, 0]
インデックス2
が使用可能)、そのセットからランダムな値を選択し、配列値の 1 つを選択した結果に設定します。これにより、衝突が解決されるまでループする必要がなくなりますが、コードが複雑になり、セットが空の場合に遭遇するリスクがあります。#2を最適に実装する方法がわからないので、ベンチマークすることをお勧めします。ベンチマークに時間をかけたくない場合は、最初のオプションを使用します。他の最適化は高速かもしれませんが、実際には遅くなる可能性があります。
このソリューションの実行時間は理論上無制限ですが、実際にはかなり迅速に終了するはずです。繰り返しますが、重要な場所で使用する前に、ベンチマークとテストを行ってください。
私が思いついた1つの可能な解決策ですが、それがどれほど「素朴」であるかはわかりません。特に端、特に遠端。
フラグの配列を作成します (ブール値) N long (スワップされた要素を表します)
各インデックスで、(flags 配列の最初の要素に従って) 既にスワップされているかどうかを確認します。スワップされている場合は、次に進みます (下記参照)。
フラグ配列を回転させ、最初の要素 (この要素を表す) を削除し、新しい「スワップされていない」要素を最後に追加します。ASIDE: これは、特に大きな N の場合、配列の内容を実際に移動する必要がないように、モジュラス配列ルックアップを使用して行うことができます。
ループ...
現在の要素を選択されたスワップされていない要素と交換し、選択された要素をフラグ配列でスワップ済みとしてマークします。次の要素にループする