生成范围内的唯一随机数 - PHP

时间:2011-04-10 15:10:23

标签: php

我需要在一个范围内生成随机的UNIQUE数字吗? 怎么办?

我可以通过

生成randoms数量
generator:
$arr=array();
$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;

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

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

14 个答案:

答案 0 :(得分:119)

具有随机顺序的数字范围的数组:

$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
)

答案 1 :(得分:13)

$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)
{
    $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内存上限的风险。混合物评估范围和计数之间的比率,并有条件地选择发电机将是两全其美的。

答案 2 :(得分:5)

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

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); 
}

Pro:这样可以避免使用in_array并且不会生成庞大的数组。因此,它很快并且保留了大量内存。

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

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

结论:最好的&#34;一般&#34;函数似乎是这个函数和@Anne函数之间的混合,它在一点点速率下效率更高。当需要一定数量并达到速率(范围/数量)时,此功能应在两种方式之间切换。因此,必须考虑到测试的复杂性/时间,必须考虑到这一点。

答案 3 :(得分:3)

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

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。

答案 4 :(得分:3)

如果你想生成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 :(得分:3)

您可以尝试下一个代码:

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;
}

答案 6 :(得分:2)

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

答案 7 :(得分:1)

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

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;
    }

}

randomNums(1100,1000,890000,899999);

答案 8 :(得分:0)

这可能会解决您的问题:

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

答案 9 :(得分:0)

我就是这样做的。

$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";

答案 10 :(得分:0)

“shuffle”方法有一个主要的错误。当数字很大时,洗牌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微秒

答案 11 :(得分:0)

只需使用此功能并传递您要生成的数字计数

<强>代码:

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;}

答案 12 :(得分:0)

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

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

suites:
    unit:
        path: .
        actor: UnitTester
        modules:
            enabled:
                # add more modules here
                - Asserts

这将非常快速地返回30,000个唯一数字。使用两倍于您需要生成的数字量的迭代值可以增加唯一数字在第一次迭代中的可能性...但是,不管它需要进行多少次迭代,其生成结果的速度都比检查数组中重复数字的速度更快循环。

答案 13 :(得分:-1)

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

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