それで、
問題
疑似乱数についてはよく知られています。「疑似」とは、実際には、一般にランダム (つまり、予測不可能) であるにもかかわらず、シーケンスは同じであり、同じジェネレーターの初期値が使用されていることを意味します。たとえば、PHP には、それを行うためのmt_srand()関数があります。例:
mt_srand(1);
var_dump(mt_rand(), mt_rand(), mt_rand());
-スクリプトを何回起動しても、生成される 3 つの数値は常に同じ順序になります。
さて、私の問題は同じことを行う方法ですが、配列をシャッフルするためです。つまり、入力配列をシャッフルおよびシードに受け入れる関数を作成したいと考えています。同じシード値内でのシャッフルは、連続した同じ順序でなければなりません。つまり、その関数を呼び出すshuffleWithSeed()
と、次のようにスクリプトを起動するたびに機能するはずです。
$input = ['foo', 'bar', 'baz'];
$test = shuffleWithSeed($input, 1000);//1000 is just some constant value
var_dump($test); //let it be ['bar', 'foo', 'baz']
$test = shuffleWithSeed($test, 1000);
var_dump($test); //let it be ['baz', 'foo', 'bar']
$test = shuffleWithSeed($test, 1000);
var_dump($test); //let it be ['baz', 'bar', 'foo']
//...
-つまり、配列に対して何回シャッフルを実行しても、次のスクリプト起動の順序付けシーケンスが 1 つのseed
値内で常に同じになるようにする必要があります。
私のアプローチ
私はこのアルゴリズムを念頭に置いています:
- 渡された乱数ジェネレーターを初期化する
seed
N
乱数を生成します。ここで、メンバーN
の数は$input
- ステップ 2 の番号を並べ替える
- 対応する番号を
$input
キーに依存させます。
私はこれを実装しました:
function shuffleWithSeed(array $input, $seed=null)
{
if(!isset($seed))
{
shuffle($input);
return $input;
}
if(!is_int($seed))
{
throw new InvalidArgumentException('Invalid seed value');
}
mt_srand($seed);
$random = [];
foreach($input as $key=>$value)
{
$random[$key] = mt_rand();
}
asort($random);
$random = array_combine(array_keys($random), array_values($input));
ksort($random);
return $random;
}
-現在、 Fisher-Yatesアルゴリズムも発見されました - しかし、それが疑似乱数 (つまり、シード) で機能するかどうかはわかりません
質問
ご覧のとおり、関数で 2 つの並べ替えを行っています。1 つ目は値による並べ替え、2 つ目はキーによる並べ替えです。
- これは1つのソートで実行できますか? それともソートなしですか?入力配列が大きくなる可能性があるので、これは避けたいです。
- しかし、私のアルゴリズムがうまくいかないのでしょうか?はいの場合、他にどのようなオプションを提案できますか?