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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5612656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 21:59:14  来源:igfitidea点击:

Generating UNIQUE Random Numbers within a range - PHP

php

提问by Sourav

i need to generate random UNIQUE numbers within a range ? how to do ?

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

i can generate randoms number by

我可以通过生成随机数

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;

I know this code is bad, so i need a better optimized code of my version ! help !

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

example: if i need to generate 3 numbers within 1 to 15 they should be like 5, 9, 1 but not 3,1,2 [with in 1 - 3 (numbers i want to generate) ]

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

回答by Anne

Array with range of numbers at random order:

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

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

Wrapped function:

包裹功能:

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

Example:

例子:

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

Result:

结果:

 Array
(
    [0] => 14
    [1] => 16
    [2] => 17
    [3] => 20
    [4] => 1
)

回答by Dan Lugg

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


I was interested to see how the accepted answer stacks up against mine. It's useful to note, a hybrid of both may be advantageous; in fact a function that conditionally uses one or the other depending on certain values:

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

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

The results:

结果:

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

If you're using a smaller range and a higher count of returned values, the accepted answer is certainly optimal; however as I had expected, larger ranges and smaller counts will take much longer with the accepted answer, as it must store every possible value in range. You even run the risk of blowing PHP's memory cap. A hybrid that evaluates the ratio between range and count, and conditionally chooses the generator would be the best of both worlds.

如果您使用较小的范围和较多的返回值,则接受的答案肯定是最佳的;然而,正如我所料,更大的范围和更小的计数将需要更长的时间来接受答案,因为它必须在范围内存储每个可能的值。您甚至会冒着超出 PHP 内存上限的风险。评估范围和计数之间的比率并有条件地选择生成器的混合体将是两全其美的。

回答by Casimir et Hippolyte

The idea consists to use the keys, when a value is already present in the array keys, the array size stays the same:

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

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: This way avoids the use of in_arrayand doesn't generate a huge array. So, it is fast and preserves a lot of memory.

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

Cons: when the rate (range/quantity) decreases, the speed decreases too (but stays correct). For a same rate, relative speed increases with the range size.(*)

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

(*) I understand that fact since there are more free integers to select (in particular for the first steps), but if somebody has the mathematical formula that describes this behaviour, I am interested by, don't hesitate.

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

Conclusion: The best "general" function seems to be a mix between this function and @Anne function that is more efficient with a little rate. This function should switch between the two ways when a certain quantity is needed and a rate (range/quantity) is reached. So the complexity/time of the test to know that, must be taken in account.

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

回答by Gazler

If you need 5 random numbers between 1 and 15, you should do:

如果您需要 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);
}

It will return false if you specify a count value larger then the possible range of numbers.

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

回答by Rich Bradshaw

If you want to generate 100 numbers that are random, but each number appearing only once, a good way would be to generate an array with the numbers in order, then shuffle it.

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

Something like this:

像这样的东西:

$arr = array();

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

shuffle($arr);

print_r($arr);

Output will look something like this:

输出将如下所示:

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
)

回答by Brotheryura

You can try next code:

您可以尝试下一个代码:

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

回答by Pete Wilson

Get a random number. Is it stored in the array already? If not, store it. If so, then go get another random number and repeat.

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

回答by jin656

When creating an application where I needed to generate 30,000 unique numbers within a larger range, I was able to cut down processing time from 25 seconds to 1.5 seconds using this method.

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

The idea is that PHP is much faster at generating random numbers than it is at checking the existence of items in an array - that is why using a while(in_array) loop can be slow.

这个想法是 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);

This will return 30,000 unique numbers extremely quickly. Using an iteration value that is double the amount of numbers you need to generate can increase the likelihood of unique numbers the first iteration... but regardless of how many iterations it takes, this will produce a result faster than checking your array for repeated numbers in a loop.

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

回答by user3615502

I guess this is probably a non issue for most but I tried to solve it. I think I have a pretty decent solution. In case anyone else stumbles upon this issue.

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

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

randomNums(1100, 1000 ,890000, 899999);

回答by Kamil Kwiecien

This probably will solve your problem:

这可能会解决您的问题:

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