Generating UNIQUE Random Numbers within a range

Php

Php Problem Overview


I need to generate random UNIQUE numbers within a range, how can I do that? I can generate random number by

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;

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

Php Solutions


Solution 1 - Php

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
)

Solution 2 - Php

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

Solution 3 - Php

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_array and doesn't generate a huge array. So, it is fast and preserves a lot of memory.

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.

Solution 4 - Php

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

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.

Solution 5 - Php

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.

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
)

Solution 6 - Php

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

Solution 7 - Php

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.

Solution 8 - Php

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.

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.

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

Solution 9 - Php

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

Solution 10 - Php

This probably will solve your problem:

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

Solution 11 - Php

This is how I would do it.

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

}

}

Then you can echo the results to check

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

Solution 12 - Php

The "shuffle" method has a MAJOR FALW. When the numbers are big, shuffle 3 billion indexs will instantly CAUSE 500 error. Here comes a best solution for really big numbers.

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

Say I want to get 10 unique random numbers from 1 billion to 4 billion.

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

PS: Execution time: 0.027 microseconds

Solution 13 - Php

Simply use this function and pass the count of number you want to generate

Code:

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

Solution 14 - Php

The best way to generate the unique random number is

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSouravView Question on Stackoverflow
Solution 1 - PhpAnneView Answer on Stackoverflow
Solution 2 - PhpDan LuggView Answer on Stackoverflow
Solution 3 - PhpCasimir et HippolyteView Answer on Stackoverflow
Solution 4 - PhpGazlerView Answer on Stackoverflow
Solution 5 - PhpRich BradshawView Answer on Stackoverflow
Solution 6 - PhpBrotheryuraView Answer on Stackoverflow
Solution 7 - PhpPete WilsonView Answer on Stackoverflow
Solution 8 - Phpjin656View Answer on Stackoverflow
Solution 9 - Phpuser3615502View Answer on Stackoverflow
Solution 10 - PhpKamil KwiecienView Answer on Stackoverflow
Solution 11 - PhpTomView Answer on Stackoverflow
Solution 12 - PhpstonyauView Answer on Stackoverflow
Solution 13 - PhpnileshkardateView Answer on Stackoverflow
Solution 14 - PhpKesavan KrishnanView Answer on Stackoverflow