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

Sou*_*rav 48 php

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

我可以生成随机数

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;
Run Code Online (Sandbox Code Playgroud)

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

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

Ann*_*nne 123

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

$numbers = range(1, 20);
shuffle($numbers);
Run Code Online (Sandbox Code Playgroud)

包裹功能:

function UniqueRandomNumbersWithinRange($min, $max, $quantity) {
    $numbers = range($min, $max);
    shuffle($numbers);
    return array_slice($numbers, 0, $quantity);
}
Run Code Online (Sandbox Code Playgroud)

例:

<?php
print_r( UniqueRandomNumbersWithinRange(0,25,5) );
?>
Run Code Online (Sandbox Code Playgroud)

结果:

 Array
(
    [0] => 14
    [1] => 16
    [2] => 17
    [3] => 20
    [4] => 1
)
Run Code Online (Sandbox Code Playgroud)

  • 如果你想要高随机数,这不是一个好的选择.想想这个函数需要多长时间才能生成1到50k之间的30个兰特数.它将首先创建一个具有5万个整数的数组,然后将尝试对其中的每一个进行洗牌,然后将从另外5万个开始切片. (15认同)
  • 如果您只需要5个随机数,只需选择数组中的前5项. (8认同)
  • 咦?`UniqueRandomNumbersWithinRange(1,15,3)`完全返回`([0] => 13 [1] => 20 [2] => 15)`. (2认同)

Dan*_*ugg 16

$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);
Run Code Online (Sandbox Code Playgroud)

我很想知道接受的答案是如何与我的一致的.值得注意的是,两者的混合可能是有利的; 实际上是一个根据特定值有条件地使用一个或另一个的函数:

# 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;
Run Code Online (Sandbox Code Playgroud)

结果:

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
Run Code Online (Sandbox Code Playgroud)

如果您使用较小的范围和较高的返回值计数,则接受的答案肯定是最佳的; 然而正如我所预料的那样,较大的范围和较小的计数将在接受的答案中花费更长的时间,因为它必须存储范围内的每个可能的值.你甚至冒着吹PHP内存上限的风险.混合物评估范围和计数之间的比率,并有条件地选择发电机将是两个世界中最好的.


Cas*_*yte 6

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

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); 
}
Run Code Online (Sandbox Code Playgroud)

Pro:这种方式避免了使用in_array并且不会生成庞大的数组.因此,它很快并且保留了大量内存.

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

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

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