6

それで、

問題

疑似乱数についてはよく知られています。「疑似」とは、実際には、一般にランダム (つまり、予測不可能) であるにもかかわらず、シーケンスは同じであり、同じジェネレーターの初期値が使用されていることを意味します。たとえば、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値内で常に同じになるようにする必要があります。

私のアプローチ

私はこのアルゴリズムを念頭に置いています:

  1. 渡された乱数ジェネレーターを初期化するseed
  2. N乱数を生成します。ここで、メンバーNの数は$input
  3. ステップ 2 の番号を並べ替える
  4. 対応する番号を$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つのソートで実行できますか? それともソートなしですか?入力配列が大きくなる可能性があるので、これは避けたいです。
  • しかし、私のアルゴリズムがうまくいかないのでしょうか?はいの場合、他にどのようなオプションを提案できますか?
4

1 に答える 1