【问题标题】:Generate predictable-suffled random array生成可预测的随机数组
【发布时间】:2013-10-29 12:28:43
【问题描述】:

所以,

问题

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

问题

如您所见,我在函数中进行了两种排序——第一种是按值,第二种是按键。

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

【问题讨论】:

    标签: php arrays algorithm random


    【解决方案1】:

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

    /**
     * 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

    【讨论】:

    • 哇,我找到了 Fisher-Yates,并且正在输入我对使用伪随机数的犹豫。您的示例表明我的想法是正确的。谢谢,现在我完全明白了
    • 有没有办法重新洗牌 $items 以获得传递的 $items 的原始顺序?
    • @nils 什么?只是...制作一个你不洗牌的副本!?
    • @nils 啊,我明白了。我不知道。会提出一个有趣的新问题。但cstheory.stackexchange.com 可能还有更多的东西
    • @nils 结果是:是的,很简单:stackoverflow.com/questions/24262147/…
    猜你喜欢
    • 1970-01-01
    • 2018-06-04
    • 2018-02-04
    • 2010-10-28
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多