【问题标题】:What is the best way to randomize an array's order in PHP without using the shuffle() function?在不使用 shuffle() 函数的情况下,在 PHP 中随机化数组顺序的最佳方法是什么?
【发布时间】:2010-09-09 02:54:15
【问题描述】:

我在一次工作面试中被问到这个问题。面试官和我不同意正确答案是什么。我想知道是否有人有这方面的任何数据。

更新:我应该提到 shuffle() 的使用是被严格禁止的......对不起。

【问题讨论】:

    标签: php arrays random


    【解决方案1】:
    shuffle($arr);
    

    :)

    编辑:我应该澄清一下……我对最佳的定义不仅涉及算法效率,还涉及代码的可读性和可维护性。使用标准库函数意味着维护更少的代码并减少阅读量。除此之外,您还可以与博士教授就最佳“真正随机”函数进行长达一年的辩论,因此总会有人在随机化问题上不同意您的观点。

    【讨论】:

      【解决方案2】:

      这是我想出的解决方案:

      function randomize_array_1($array_to_randomize) {
          $new_array = array();
          while (count($array_to_randomize) > 0) {
              $rand_num = rand(0, count($array_to_randomize)-1);
              $extracted = array_splice($array_to_randomize, $rand_num, 1);
              $new_array[] = $extracted[0];
          }
          return $new_array;
      }
      

      这是他的解决方案:

      function randomize_array_2($array_to_randomize) {
          usort($array_to_randomize, "rand_sort");
          return $array_to_randomize;
      }
      function rand_sort($a, $b) {
          return rand(-1, 1);
      }
      

      我对这两种方法进行了一系列试验(每个试验 1,000,000 次),速度差异可以忽略不计。然而,在检查结果的实际随机性后,我对分布的不同感到惊讶。这是我的结果:

      randomize_array_1:
          [2, 3, 1] => 166855
          [2, 1, 3] => 166692
          [1, 2, 3] => 166690
          [3, 1, 2] => 166396
          [3, 2, 1] => 166629
          [1, 3, 2] => 166738
      
      randomize_array_2:
          [1, 3, 2] => 147781
          [3, 1, 2] => 73972
          [3, 2, 1] => 445004
          [1, 2, 3] => 259406
          [2, 3, 1] => 49222
          [2, 1, 3] => 24615
      

      如您所见,第一种方法提供了几乎完美的分布,表明它或多或少是真正随机的,而第二种方法则无处不在。

      【讨论】:

      • 我刚刚浏览了一些老问题并遇到了这个问题。你提到他到处都是。当然,这就是随机性。
      • @Peter One 预计在多次试验之后,每个排列将出现大致相同的次数。在如此多的试验中,一个排列比另一个排列多 18 倍这一事实意味着每个排列发生的概率不相等。
      【解决方案3】:

      您可以使用Fisher-Yates shuffle

      【讨论】:

      • 我实现了 Fisher-Yates Shuffle 非常快,虽然它没有提供比我尝试的其他一些方法更多的随机结果,但它明显更快(大约是总时间的 1/4)。也就是说,它仍然花费了 shuffle() 的 4 倍左右。
      【解决方案4】:

      他可能在测试你大多数人在实施洗牌算法时犯的一个相对常见的错误(这实际上也是几年前涉及在线扑克网站的controversy 的中心)

      洗牌方式不正确:

      for (i is 1 to n) Swap i with random position between 1 and n

      正确的洗牌方式:

      for (i is 1 to n) Swap i with random position between i and n

      画出这些案例的概率分布,很容易看出为什么第一个解决方案不正确。

      【讨论】:

      • 老实说,我已经阅读了您的示例几次,但看不出它们有何不同;当然,解释是不同的,但“for (i is 1 to n)”部分是相同的。
      【解决方案5】:

      “正确”的方式非常模糊。对数组进行排序的最佳(最快/最简单/最优雅)就是使用内置的 shuffle() 函数。

      【讨论】:

        【解决方案6】:

        PHP 有一个内置函数 --> shuffle() 。我会说这应该做你喜欢的事情,但它很可能不会完全“随机”。

        查看http://computer.howstuffworks.com/question697.htm,了解为什么从计算机获得完全随机性非常非常困难。

        【讨论】:

          【解决方案7】:

          简答:PHP 的 array_rand() 函数

          鉴于禁止使用 shuffle 功能,我将使用$keys = array_rand($myArray, count($myArray)) 以随机顺序从$myArray 返回一个键数组。从那里可以很容易地将它们重新组合成一个随机的新数组。类似的东西:

          $keys = array_rand($myArray, count($myArray));
          $newArray = array();
          
          foreach ($keys as $key) {
          $newArray[$key] = $myArray[$key];
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-05-18
            • 1970-01-01
            • 1970-01-01
            • 2012-03-17
            • 2012-07-25
            相关资源
            最近更新 更多