php - 生成可预测的随机数组

标签 php arrays algorithm random

所以,

问题

众所周知pseudo-random numbers . “伪”实际上意味着,尽管它们通常是随机的(即不可预测的),但它们的顺序仍然相同,其中使用了相同的生成器初始值。例如,在 PHP 中有 mt_srand()功能来做到这一点。示例:

mt_srand(1);
var_dump(mt_rand(), mt_rand(), mt_rand());

-无论我们启动脚本多少次:生成的三个数字的顺序总是相同的。

现在,我的问题是如何做同样的事情——但要洗牌数组。 IE。我想创建一个函数,它将接受输入数组以随机播放和种子。在相同的种子值内,洗牌必须具有连续的相同顺序。 IE。让我们调用该函数 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']
//...

-即无论我们对数组进行多少次洗牌 - 我希望下一个脚本启动顺序在一个 seed 值内始终相同。

我的方法

我想到了这个算法:

  1. 使用传递的种子初始化随机数生成器
  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算法 - 但不确定它是否可以使用伪随机数(即种子)

问题

如您所见,我在我的函数中进行了两种排序 - 首先是按值,其次是按键。

  • 这可以用一种方式完成吗?或者根本没有排序?输入数组可能很大,所以我想避免这种情况。
  • 但是,可能是我的算法不好?如果是,可以建议哪些其他选项?

最佳答案

这是我不久前为此目的实现的一个函数的复制和粘贴:

/**
 * Shuffles an array in a repeatable manner, if the same $seed is provided.
 * 
 * @param array &$items The array to be shuffled.
 * @param integer $seed The result of the shuffle will be the same for the same input ($items and $seed). If not given, uses the current time as seed.
 * @return void
 */
protected function seeded_shuffle(array &$items, $seed = false) {
    $items = array_values($items);
    mt_srand($seed ? $seed : time());
    for ($i = count($items) - 1; $i > 0; $i--) {
        $j = mt_rand(0, $i);
        list($items[$i], $items[$j]) = array($items[$j], $items[$i]);
    }
}

它实现了一个简单的 Fisher-Yates shuffle带有种子随机数生成器。

关于php - 生成可预测的随机数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19658239/

相关文章:

php - 如何在响应中返回数组

java - 使用随机类填充数组,然后打印它的值

java - 在有障碍物的二维矩阵中找到到达给定目标单元格的最短路径

c++ - 在计算列表中获取前 n 项的最快方法是什么?

c++ - 更改相邻顶点的值并删除自循环

当 pm.max_children > 506 时 PHP 7.2 无法启动

php - 将 TinyInt 值更改为 1 PHP

c++ - 在函数中填充指针数组

php - 如何使用 REST API + PHP 将图片上传到 parse.com?

php - 具有多条记录的 LAST_INSERT_ID() 插入 MySQL