【问题标题】:PHP's array_rand() not really random?PHP array_rand() 不是真的随机?
【发布时间】:2014-05-07 15:33:03
【问题描述】:

我正在编写一些代码来随机化演示列表。同一演示文稿无法连续播放。

$d 数组将是演示文稿 ID 的列表以及演示文稿应循环播放的次数。

下面的代码运行良好,但结果并不是真正随机的。当我开始一遍又一遍地看到相同的模式时,我正在调试。看看这个输出:

ighbajafpbailgjacbiaeldiqjaphafgdjcbapsaebjfdkcknijhbdgecaimabodalkfbgbhacbhnrjeofbdjbfhegmbpdkialmbocnliaebfaimcabchgoecbcdimgepnfjgfbfbohdahdkjgneaebha

ighbajafpbailgjacbiaeldiqjaphafgdjcbapsaebjfdkcknijhbdgecaimabodalkfbgbhacbhnrjeofbdjbfhegmbpdkialmbocnliaebfaimcabchgoecbcdimgepnfjgfbfbohdahdkjgneaebha

这两个相隔 4 次。它们是相同的。 4 次运行后,相同的字符串。再运行 4 次,相同的字符串。事实上,当我运行它时,我似乎得到了相同的 4 个字符串。

我的代码在下面,有人能指出我可能有什么问题吗?如果我什么都没做,为什么“rand”不是随机的?我该如何解决这个问题?

$d = array(
    array('a', '20'), array('b', '20'), array('c', '10'), array('d', '10'), array('e', '10'), array('f', '10'), array('g', '10'), array('h', '10'), array('i', '10'), array('j', '10'), array('k', '5'), array('l', '5'), array('m', '5'), array('n', '5'), array('o', '5'), array('p', '5'), array('q', '1'), array('r', '1'), array('s', '1'));
$out = randomizeArray($d);
//var_dump($out);

function randomizeArray ($data) {
    // Step 1: Make an array of the id's with repeats for count.
    $rarray = array();
    foreach ($data as $i => $v) {
        while ($data[$i][1] > 0) {
            array_push($rarray, $data[$i][0]);
            $data[$i][1]--;
        }
    }
    // Step 2: Randomize.
    $stat = 1;
    while ($stat == '1') {
        //echo "<br><br>Randomizing Array: <br>";
        $stat = rarr($rarray);
    }
    return $stat;
}
function rarr ($a) {
    $r = array();
    $last = "";
    while ($a) {
        $rand = array_rand($a, 1);
        // Does this value match the last one we got?
        if ($a[$rand] != $last) {
            // Nope. Transfer to our $r array.
            echo $a[$rand];
            array_push($r, $a[$rand]);
            $last = $a[$rand];
            unset($a[$rand]);
        } else {
            // We have a match between our "last" presentation and the one we just selected.
            // We need to scan our array and verify that we still have different values.
            $check = $a[$rand];
            foreach ($a as $c) {
                if ($check != $c) {
                    // We have at least 2 different values in our array still.
                    // Rerun the while loop
                    continue 2;
                }
            }
            // All of the values left in our array are repeats.
            // That's no good, so return an error and rerun.
            return 1;
        }
    }
    // Everything is awesome. Return the randomized array.
    return $r;
}

【问题讨论】:

  • 这太多了。期望的随机输出是什么?由随机字母组成的一定长度的字符串?

标签: php random


【解决方案1】:

据我所知,解决方案是在第 2 步行之前添加:

shuffle($rarray);

似乎解决了一点问题。重复精确到 47 次。

如果你只是在 rarr 函数中添加它:

while ($a) {
    shuffle($a);

如果将精确重复 52 次​​p>

看来实际上是array_rand函数的问题。将 array_rand 更改为 mt_rand,如下代码所示:

<?php
$d = array(
    array('a', '20'), array('b', '20'), array('c', '10'), array('d', '10'), array('e', '10'), array('f', '10'), array('g', '10'), array('h', '10'), array('i', '10'), array('j', '10'), array('k', '5'), array('l', '5'), array('m', '5'), array('n', '5'), array('o', '5'), array('p', '5'), array('q', '1'), array('r', '1'), array('s', '1'));

    for ($i=0; $i<10000; ++$i) {
        //ho "x";
        $out = randomizeArray($d);
        echo implode('',$out)."<br />";   
    }    


//var_dump($out);

function randomizeArray ($data) {
    // Step 1: Make an array of the id's with repeats for count.
    $rarray = array();
    foreach ($data as $i => $v) {
        while ($data[$i][1] > 0) {
            array_push($rarray, $data[$i][0]);
            $data[$i][1]--;
        }
    }
    // Step 2: Randomize.
    $stat = 1;
    while ($stat == '1') {
        //echo "<br><br>Randomizing Array: <br>";
        $stat = rarr($rarray);
    }
    return $stat;
}
function rarr ($a) {
    $r = array();
    $last = "";
    while ($a) {
        $rand = mt_rand(0,count($a)-1);
        // Does this value match the last one we got?
        if ($a[$rand] != $last) {
            // Nope. Transfer to our $r array.
           // echo $a[$rand];
            array_push($r, $a[$rand]);
            $last = $a[$rand];
            unset($a[$rand]);
            $a = array_values($a);
        } else {
            // We have a match between our "last" presentation and the one we just selected.
            // We need to scan our array and verify that we still have different values.
            $check = $a[$rand];
            foreach ($a as $c) {
                if ($check != $c) {
                    // We have at least 2 different values in our array still.
                    // Rerun the while loop
                    continue 2;
                }
            }
            // All of the values left in our array are repeats.
            // That's no good, so return an error and rerun.
            return 1;
        }
    }
    // Everything is awesome. Return the randomized array.
    return $r;
}

使字符串真正独一无二。

我真的很好奇是否有人可以解释这是 PHP 错误或“功能”

【讨论】:

  • 谢谢,实际上我只是用 mt_rand() 函数重写了它。我考虑过使用 shuffle,但如果它使用相同的逻辑呢?
【解决方案2】:

我仍然对为什么这个功能不能正常工作感兴趣。我今天尝试了一下并添加了

srand();

在启动 randomizeArray 函数之前。我留下了问题中的代码(所以只有array_rand)并添加了循环来测试10000个随机字符串。

似乎有帮助。字符串现在是完全随机的,和使用 mt_rand 一样。

我查看了文档http://au1.php.net/manual/en/function.array-rand.php,这里只有信息“4.2.0 随机数生成器是自动播种的。”。但我还查看了http://au1.php.net/manual/pl/function.array-rand.php 的波兰文档 - 有更多关于它的信息,将其翻译成英文:“从 PHP 4.2.0 开始,无需启动生成器 srand() 或 mt_srand(),因为它是自动完成的”

好吧,我在 PHP 5.5.12 上对其进行了测试,实际上它似乎不是自动完成的。我还检查了如果我将启动 mt_srand() 而不是 srand() 会发生什么,无论是否有种子。似乎根本没有帮助。只有使用 srand() 才能使 array_rand 实际上是随机函数。

【讨论】:

  • 我已经在bugs.php.net/bug.php?id=67233 报告了错误,如果有人有类似的问题,您可以投票或添加评论。
  • 他们将此报告作为重复报告关闭。似乎出现了这个或类似的错误,但不知道他们为什么不尝试修复它们。所以最终的答案是这是一个错误。在 php 中使用随机函数作为 array_rand,您应该始终在目标环境中对其进行良好测试,因为值可能不是随机的。
【解决方案3】:

rand() 和 array_rand() 是伪随机函数

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-07
    • 2012-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多