在一定范围内生成唯一的随机数


Generating UNIQUE Random Numbers within a range

我需要在一个范围内生成随机的唯一数字,我该怎么做?我可以通过以下方式生成随机数

generator:
$arr = [];
$x = rand($min, $max);
$len = count($arr);
$flag = 0;
for($i = 0; $i < $len; $i++)
{
 if ($flag === 1)
   goto generator;
 if ($x === $arr[$i])
   $flag = 1;
}
$arr[$index] = $x;
$index++; 
goto generator;

我知道这段代码不好,所以我需要一个更好的优化代码!帮助!

例:如果我需要在 3 到 15 内生成 15 个数字,它们应该像 5、9、1 而不是 3,1,2 [在 1 - 3(我想生成的数字(]

随机顺序排列数字范围的数组:

$numbers = range(1, 20);
shuffle($numbers);

包装功能:

function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $quantity);
}

例:

<?php
print_r( UniqueRandomNumbersWithinRange(0,25,5) );
?>

结果:

 Array
(
    [0] => 14
    [1] => 16
    [2] => 17
    [3] => 20
    [4] => 1
)
$len = 10;   // total number of numbers
$min = 100;  // minimum
$max = 999;  // maximum
$range = []; // initialize array
foreach (range(0, $len - 1) as $i) {
    while(in_array($num = mt_rand($min, $max), $range));
    $range[] = $num;
}
print_r($range);
<小时 />

我很想知道接受的答案如何与我的答案相提并论。值得注意的是,两者的混合可能是有利的;实际上,一个根据某些值有条件地使用其中一个的函数:

# The accepted answer
function randRange1($min, $max, $count)
{
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $count);
}
# My answer
function randRange2($min, $max, $count)
{
    $i = 0;
    $range = array();
    while ($i++ < $count) {
        while(in_array($num = mt_rand($min, $max), $range));
        $range[] = $num;
    }
    return $range;
}
echo 'randRange1: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: small range, high count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 9999, 5000);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange1: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange1(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;
echo 'randRange2: high range, small count' . PHP_EOL;
$time = microtime(true);
randRange2(0, 999999, 6);
echo (microtime(true) - $time) . PHP_EOL . PHP_EOL;

结果:

randRange1: small range, high count
0.019910097122192
randRange2: small range, high count
1.5043621063232
randRange1: high range, small count
2.4722430706024
randRange2: high range, small count
0.0001051425933837
如果您使用较小的范围和较高的返回值计数,则接受的答案

肯定是最佳的;但是,正如我所料,较大的范围和较小的计数对于接受的答案将花费更长的时间,因为它必须存储范围内的每一个可能的值。你甚至冒着吹掉PHP内存上限的风险。评估范围和计数之间的比率并有条件地选择生成器的混合体将是两全其美的选择。

这个想法包括使用键,当数组键中已经存在一个值时,数组大小保持不变:

function getDistinctRandomNumbers ($nb, $min, $max) {
    if ($max - $min + 1 < $nb)
        return false; // or throw an exception
    $res = array();
    do {
        $res[mt_rand($min, $max)] = 1;
    } while (count($res) !== $nb);
    return array_keys($res); 
}

优点:这种方式避免了使用in_array,也不会生成巨大的数组。因此,它速度很快并保留了大量内存。

缺点:当速率(范围/数量(降低时,速度也会降低(但保持正确(。对于相同的速率,相对速度随着范围大小的增加而增加。(*(

(*( 我理解这一事实,因为有更多的自由整数可供选择(特别是第一步(,但如果有人有描述这种行为的数学公式,我很感兴趣,不要犹豫。

结论:最好的"通用"函数似乎是这个函数和@Anne函数之间的混合,后者效率更低,速率更低。当需要一定数量并达到速率(范围/数量(时,此功能应在两种方式之间切换。因此,必须考虑到测试的复杂性/时间才能知道这一点。

如果要生成 100 个随机数字,但每个数字只出现一次,一个好方法是生成一个按顺序排列数字的数组,然后对其进行洗牌。

像这样:

$arr = array();
for ($i=1;$i<=101;$i++) {
    $arr[] = $i;
}
shuffle($arr);
print_r($arr);

输出将如下所示:

Array
(
    [0] => 16
    [1] => 93
    [2] => 46
    [3] => 55
    [4] => 18
    [5] => 63
    [6] => 19
    [7] => 91
    [8] => 99
    [9] => 14
    [10] => 45
    [11] => 68
    [12] => 61
    [13] => 86
    [14] => 64
    [15] => 17
    [16] => 27
    [17] => 35
    [18] => 87
    [19] => 10
    [20] => 95
    [21] => 43
    [22] => 51
    [23] => 92
    [24] => 22
    [25] => 58
    [26] => 71
    [27] => 13
    [28] => 66
    [29] => 53
    [30] => 49
    [31] => 78
    [32] => 69
    [33] => 1
    [34] => 42
    [35] => 47
    [36] => 26
    [37] => 76
    [38] => 70
    [39] => 100
    [40] => 57
    [41] => 2
    [42] => 23
    [43] => 15
    [44] => 96
    [45] => 48
    [46] => 29
    [47] => 81
    [48] => 4
    [49] => 33
    [50] => 79
    [51] => 84
    [52] => 80
    [53] => 101
    [54] => 88
    [55] => 90
    [56] => 56
    [57] => 62
    [58] => 65
    [59] => 38
    [60] => 67
    [61] => 74
    [62] => 37
    [63] => 60
    [64] => 21
    [65] => 89
    [66] => 3
    [67] => 32
    [68] => 25
    [69] => 52
    [70] => 50
    [71] => 20
    [72] => 12
    [73] => 7
    [74] => 54
    [75] => 36
    [76] => 28
    [77] => 97
    [78] => 94
    [79] => 41
    [80] => 72
    [81] => 40
    [82] => 83
    [83] => 30
    [84] => 34
    [85] => 39
    [86] => 6
    [87] => 98
    [88] => 8
    [89] => 24
    [90] => 5
    [91] => 11
    [92] => 73
    [93] => 44
    [94] => 85
    [95] => 82
    [96] => 75
    [97] => 31
    [98] => 77
    [99] => 9
    [100] => 59
)

如果你需要 5 个介于 1 和 15 之间的随机数,你应该这样做:

var_dump(getRandomNumbers(1, 15, 5));
function getRandomNumbers($min, $max, $count)
{
    if ($count > (($max - $min)+1))
    {
        return false;
    }
    $values = range($min, $max);
    shuffle($values);
    return array_slice($values,0, $count);
}

如果指定的计数值大于可能的数字范围,它将返回 false。

你可以试试下一个代码:

function unique_randoms($min, $max, $count) {
 $arr = array();
 while(count($arr) < $count){
      $tmp =mt_rand($min,$max);
      if(!in_array($tmp, $arr)){
         $arr[] = $tmp;
      }
 }
return $arr;
}

获取一个随机数。它已经存储在数组中了吗?如果没有,请存储它。如果是这样,那么去获取另一个随机数并重复。

在创建需要在更大范围内生成 30,000 个唯一编号的应用程序时,我能够使用此方法将处理时间从 25 秒缩短到 1.5 秒。

这个想法是PHP在生成随机数时比在检查数组中项目是否存在时要快得多 - 这就是为什么使用while(in_array(循环可能很慢的原因。

$count = 0;
$collectNumbers = [];
while ($count < 30000) {
for ($i = 0; $i < 60000; $i++) {
$rand = mt_rand(1, 100000);
$collectNumbers[] = $rand;
}
$unique = array_unique($collectNumbers);
$count = count($unique);
}
$finalArray = array_slice($unique, 0, 30000);

这将非常快速地返回 30,000 个唯一编号。使用比您需要生成的数字量多一倍的迭代值可以增加第一次迭代时唯一数字的可能性...但是,无论需要多少次迭代,这都会比在循环中检查数组中的重复数字更快地产生结果。

这可能会解决您的问题:

<?php print_r(array_rand(range(1,50), 5)); ?>
我想

这对大多数人来说可能不是问题,但我试图解决它。 我想我有一个相当不错的解决方案。以防其他人偶然发现这个问题。

function randomNums($gen, $trim, $low, $high)
{
    $results_to_gen = $gen;
    $low_range      = $low;
    $high_range     = $high;
    $trim_results_to= $trim;
    $items = array();
    $results = range( 1, $results_to_gen);
    $i = 1;
    foreach($results as $result)
    {
        $result = mt_rand( $low_range, $high_range);
        $items[] = $result;
    }

    $unique = array_unique( $items, SORT_NUMERIC);
    $countem = count( $unique);
    $unique_counted = $countem -$trim_results_to;
    $sum = array_slice($unique, $unique_counted);

    foreach ($sum as $key)
    {
        $output = $i++.' : '.$key.'<br>';
        echo $output;
    }
}

随机数(1100, 1000 ,890000, 899999(;

这就是我会这样做的方式。

$randnum1 = mt_rand(1,20);
$nomatch = 0;
while($nomatch == 0){
$randnum2 = mt_rand(1,20);
if($randnum2 != $randnum1){
$nomatch = 1;
}
}
$nomatch = 0;
while($nomatch == 0){
$randnum3 = mt_rand(1,20);
if(($randnum3 != $randnum1)and($randnum3 != $randnum2)){
$nomatch = 1;
}
}

然后你可以回显结果进行检查

echo "Random numbers are " . $randnum1 . "," . $randnum2 . ", and " . $randnum3 . "'n";

"shuffle" 方法有一个主要的 FALW。当数字很大时,洗牌 30 亿个索引将立即导致 500 错误。这是真正大数字的最佳解决方案。

function getRandomNumbers($min, $max, $total) {
    $temp_arr = array();
    while(sizeof($temp_arr) < $total) $temp_arr[rand($min, $max)] = true;
    return $temp_arr;
}

假设我想得到 10 亿到 40 亿之间的 10 个唯一随机数。

$random_numbers = getRandomNumbers(1000000000,4000000000,10);

PS:执行时间:0.027微秒

只需使用此函数并传递要生成的数字计数

法典:

function randomFix($length)
{
    $random= "";
srand((double)microtime()*1000000);
$data = "AbcDE123IJKLMN67QRSTUVWXYZ";
$data .= "aBCdefghijklmn123opq45rs67tuv89wxyz";
$data .= "0FGH45OP89";
for($i = 0; $i < $length; $i++)
{
    $random .= substr($data, (rand()%(strlen($data))), 1);
}
return $random;}

生成唯一随机数的最佳方法是

<?php
     echo md5(uniqid(mt_rand(), true).microtime(true));
?>