Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 12 months ago.
Improve this question
i want to generate 630 random numbers between 1 and 20. So far, so good. However, the sum of the numbers between 1 and 20 of these 630 produced should not exceed 3000. I could not write such an algorithm. Could you help?
Your problem is that 3000 / 630 = 4.76 which is far from the average number between 1-20. What we can do is constrain the random numbers' ranges to accommodate this, and get a distribution slant with an average sum approximate to the maximum sum.
Given the required maximum average of 4.76, we can for example generate 1/4 of the random numbers as between 1-20, and 3/4 as between 1-4 to slant the distribution:
function get_slanted_rands() {
$rands = [];
for($i = 1; $i <= 630; $i++) {
// For every 4th iteration, get random from the full range
$rands[] = $i % 4 === 0
? mt_rand(1,20)
: mt_rand(1,4);
}
$sum = array_sum($rands);
// If the sum is over the max, recall:
if($sum > 3000) {
return get_slanted_rands();
}
// Log the average for debugging:
$avg = round($sum / count($rands), 2);
return compact('sum', 'avg', 'rands');
}
Notice that the function checks the sum and recalls itself on the odd occasion that the sum exceeds 3000. On a typical call, the sum 3000 isn't exceeded with the above "calibration" — since we split 1:3 in favor of the lower range. But random is random, so there's no "average" guaranteed.
Let's test-drive this contraption for 100 iterations and see what we get:
$test = [];
for($t = 1; $t <= 100; $t++) {
$test[] = get_slanted_rands();
}
$sums = array_column($test, 'sum');
rsort($sums);
echo "==== SUMS ====\n" . implode(', ', $sums) . "\n\n";
$avgs = array_column($test, 'avg');
rsort($avgs);
echo "==== AVGS ====\n" . implode(', ', $avgs);
This yields for the following (reverse sorted), sums between 2600+ and 3000 and averages between 4.75 and 4.19. (On average, ~1:100 iterations exceeds 3000 and is recalled.)
==== SUMS ====
2993, 2985, 2975, 2969, 2959, 2947, 2941, 2933, 2926, 2919, 2919, 2917, 2911, 2909, 2908, 2904, 2903, 2901, 2894, 2894, 2892, 2886, 2884, 2884, 2882, 2881, 2879, 2876, 2871, 2869, 2867, 2863, 2861, 2853, 2852, 2852, 2851, 2851, 2850, 2848, 2844, 2843, 2842, 2838, 2838, 2837, 2837, 2837, 2836, 2834, 2834, 2826, 2826, 2825, 2820, 2814, 2813, 2812, 2802, 2801, 2799, 2799, 2799, 2798, 2796, 2795, 2792, 2789, 2789, 2787, 2784, 2784, 2784, 2783, 2778, 2778, 2776, 2768, 2767, 2764, 2762, 2754, 2754, 2747, 2743, 2737, 2736, 2728, 2727, 2724, 2723, 2721, 2719, 2718, 2707, 2706, 2690, 2673, 2642
==== AVGS ====
4.75, 4.74, 4.72, 4.71, 4.7, 4.68, 4.67, 4.66, 4.64, 4.63, 4.63, 4.63, 4.62, 4.62, 4.62, 4.61, 4.61, 4.6, 4.59, 4.59, 4.59, 4.58, 4.58, 4.58, 4.57, 4.57, 4.57, 4.57, 4.56, 4.55, 4.55, 4.54, 4.54, 4.53, 4.53, 4.53, 4.53, 4.53, 4.52, 4.52, 4.51, 4.51, 4.51, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.49, 4.49, 4.48, 4.48, 4.47, 4.47, 4.46, 4.45, 4.45, 4.44, 4.44, 4.44, 4.44, 4.44, 4.44, 4.43, 4.43, 4.43, 4.42, 4.42, 4.42, 4.42, 4.42, 4.41, 4.41, 4.41, 4.39, 4.39, 4.39, 4.38, 4.37, 4.37, 4.36, 4.35, 4.34, 4.34, 4.33, 4.33, 4.32, 4.32, 4.32, 4.32, 4.31, 4.3, 4.3, 4.27, 4.24, 4.19
You can always tweak the slanting condition if you feel it should on average be closer to 3000... Or simply add a recall condition with a "minimum sum" check and "brute force" it. But this suffices to give you the general idea: You need to generate random numbers of a limited range in proportion to what your "average for target sum" demands. Demo at 3v4l: https://3v4l.org/fG74X
Finally, a sample of the sort of distribution you get. Given as "number" => "instances" in a set of 630. It's heavily slanted to 1, 2, 3, 4 there — and that's how it must be to meet your specs!
$nums = get_slanted_rands();
$distribution = array_count_values($nums['rands']);
arsort($distribution);
print_r($distribution);
// yields:
[3] => 143
[4] => 125
[2] => 125
[1] => 110
[8] => 13
[9] => 12
[18] => 12
[19] => 10
[11] => 9
[5] => 8
[17] => 8
[14] => 7
[12] => 7
[10] => 7
[16] => 7
[6] => 7
[15] => 6
[7] => 6
[20] => 5
[13] => 3
$result = [];
$sumCurrent = 0;
$barrier = 3000 / 630;
for ($i = 1; $i <= 630; $i++) {
$sumBarrier = intval($i * $barrier);
while (true) {
$number = random_int(1, 20);
if ($sumCurrent + $number <= $sumBarrier) {
break;
}
}
$result[] = $number;
$sumCurrent += $number;
}
$sum = array_sum($result);
$occurrences = array_count_values($result);
uksort($occurrences, fn($key1, $key2) => $key1 <=> $key2);
print_r($result); echo "\n";
print_r($sum); echo "\n";
print_r($occurrences); echo "\n";
Related
I'm trying to figure out how to calculate the median of an array of randomly generated numbers. I have the array all set up, but I'm having trouble putting together a function for the calcuation.
This is what I have so far:
//array
$lessFifty = array();
$moreFifty = array();
//number generation
for ($i = 0; $i<=30; $i++) {
$number = rand(0, 100);
//Sorting <50>
if ($number < 50 ) {
$lessFifty[] = $number;
} else {
$moreFifty[] = $number;
}
}
echo print_r($lessFifty);
echo "<br>" ;
echo print_r($moreFifty);
//Average
echo "<p> Average of values less than fifty: </p>";
print array_sum($lessFifty) / count($lessFifty) ;
echo "<p> Average of values greater than fifty: </p>" ;
print array_sum($moreFifty) / count($moreFifty) ;
//Median
$func = function (median ($array, $output = $median)){
if(!is_array($array)){
return FALSE;
}else{
switch($output){
rsort($array);
$middle = round(count($array) 2);
$total = $array[$middle-1];
break;
return $total;
}
}
echo $func ;
I'm pretty sure that I'm doing this median section completely wrong. I'm just learning and its proving to be a challenge.
Be careful about how you write your for() loop. If you want 30 entries, then you should not use <= or you will end up with 31 because $i starts with 0.
Build an array of the random numbers, then sort them.
Then determine if you have a central entry (odd array length) or if you need to average the middle two entries (even array length).
Here is a modern implementation of a median method posted in 2022 on CodeReview.
Code: (Demo)
$limit = 30; // how many random numbers do you want? 30 or 31?
for ($i = 0; $i < $limit; ++$i) {
$numbers[] = rand(0, 100);
}
var_export($numbers);
//echo "\n---\nAverage: " , array_sum($numbers) / $limit;
echo "\n---\n";
sort($numbers);
$count = sizeof($numbers); // cache the count
$index = floor($count/2); // cache the index
if (!$count) {
echo "no values";
} elseif ($count & 1) { // count is odd
echo $numbers[$index];
} else { // count is even
echo ($numbers[$index-1] + $numbers[$index]) / 2;
}
Possible Output:
array (
0 => 27,
1 => 24,
2 => 84,
3 => 43,
4 => 8,
5 => 51,
6 => 60,
7 => 86,
8 => 9,
9 => 48,
10 => 67,
11 => 20,
12 => 44,
13 => 85,
14 => 6,
15 => 63,
16 => 41,
17 => 32,
18 => 64,
19 => 73,
20 => 43,
21 => 24,
22 => 15,
23 => 19,
24 => 9,
25 => 93,
26 => 88,
27 => 77,
28 => 11,
29 => 54,
)
---
43.5
After sorting, elements [14] and [15] hold 43 and 44 respectively. The average of these "middle two" values is how the result is determined. (Hardcoded numbers demo)
If you want a short, inflexible, hardcoded snippet, then you can use 30 and 14 and 15 as your predetermined size and indexes.
for ($i = 0; $i < 30; ++$i) {
$numbers[] = rand(0, 100);
}
sort($numbers);
echo ($numbers[14] + $numbers[15]) / 2;
I have two arrays of numbers, one containing a lot of numbers, one only a few. There are no duplicates within or between arrays:
$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_merge(array_diff($all, $few));
I now want to calculate the differences between each of the "few" numbers and all of the "many" that follow it but come before the next of the "few". For example, among $many, only 28 falls between 27 and 29 from $few, so I want to calculate the difference between 28 and 27. No other differences to 27 are calculated, because no other $many fall between 27 and 29. For 19 from $few I will calculate the differences to 20, 21, 22, 23, 24, 25 and 26, because they all lie between 19 and the next number from $few, which is 27.
To calculate the differences, I use loops. Here is a somewhat simplified code (which ignores the fact that there is no index [$i + 1] for the last number in $few):
$differences = array();
for($i = 0; $i < count($few); $i++) {
foreach($many as $m) {
if($m > $few[$i] && $m < $few[$i + 1]) {
$differences[] = $m - $few[$i];
}
}
}
If I have huge arrays, the loops will take a long time to run. So:
Is there a better way to calculate the differences, without using loops?
The resulting $differences looks like this:
Array $many $few
( ↓ ↓
[0] => 1 // 8 - 7 = 1
[1] => 2 // 9 - 7
[2] => 3 // 10 - 7
[3] => 1 // 12 - 11
[4] => 2
[5] => 3
[6] => 4
[7] => 5
[8] => 6
[9] => 7
[10] => 1
[11] => 2
[12] => 3
[13] => 4
[14] => 5
[15] => 6
[16] => 7
[17] => 1
[18] => 1
[19] => 2
[20] => 3
[21] => 4
[22] => 5
[23] => 6
[24] => 1
[25] => 2
[26] => 3
[27] => 1
[28] => 2
)
My basic reasoning is that as a human, I don't see two arrays that I compare:
... 16 17 18 | 20 21 22 23 24 25 26 | 28 29 30 31 ...
exclude | include | exclude
19 (27)
But rather one number line that I go along from one number to the next, and when I meet one marked "few" I will calculate all the differences to each of the following numbers, until I meet another one marked "few":
... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...
... m m m f m m m m m m m f m m m m ...
↑ ↑ ... ↑
start calculate stop
Because it is sorted, I don't have to go over the whole $many-array number by number for every number from $few. So can we somehow take the fact into account that the arrays are ordered? Or maybe build one array that contains the markers ("f", "m") and the numbers as keys? E.g.:
$all = array("drop this", "m", "m", "m", "m", "m", "m", "f", ...);
unset($all[0]); // drops the first element with index 0
Apart from the two calls to sort(), all you need is a single loop through $many.
// Input data provided in the question
$all = range(1, 50);
$few = array(7, 11, 19, 27, 29, 36, 40, 43);
$many = array_values(array_diff($all, $few));
// Display the values to see what we are doing
echo('$few = ['.implode(' ', $few)."]\n");
echo('$many = ['.implode(' ', $many)."]\n");
//
// The actual algorithm starts here
// Sort both $few and $many
// it works fast enough and it is required for the rest of the algorithm
sort($few);
sort($many);
// Be sure the last value of $few is larger than the last value of $many
// This is needed to avoid extra checking for the last element of $few inside the loop
if (end($few) < end($many)) {
array_push($few, end($many) + 1);
}
// Extract the first two items from $few
$current = array_shift($few);
$next = array_shift($few);
// This is the result
$differences = array();
// Run only once through $many, check each item against $next
// subtract $current from it; advance when $next was reached
foreach ($many as $item) {
// Skip the items smaller than the first element from $few
if ($item < $current) {
continue;
}
// If the next element from $few was reached then advance to the next interval
while ($next < $item) {
$current = $next;
$next = array_shift($few);
}
// Here $current < $item < $next
// This echo() is for debug purposes
echo('$current = '.$current.'; $item = '.$item.'; $next = '.$next.'; difference='.($item - $current)."\n");
// Store the difference
$differences[] = $item - $current;
}
In PHP I have an Array like this:
$BulkArray[$i]
This Array is feed with plenty of Numbers (e.g. 1 => 100, 2 => 300, 3 => 100, and so on).
Now I want to find within the whole range of numbers, the greatest succession of a number equal or less than 500. I want to write the number of succession.
for example I have the array
1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100
as you can see, number 1,2 & 3 are together 500. So this is the first succession.
2,3,4,5 are also 500 together. (This succession(4) is bigger than the first succession(3))
And so on,then you will get the highest succession: 3,4,5,6,7,8 (succession with 6 numbers) which is 350 (but lower than 500m, as we searched for it)
Now, how can I write with the Array:
$BulkArray[$i], that the highest succession is 6 ?
Because 6 is the highest succession found in the whole array for 500!
(It's for categorizing specific Carparts)
The answer of User "fas M" here again, with little improvement:
<?php //lets call your $BulkArray = $values;
$values=array( 1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100 );
$sum=0; // to sum up until 500
$Vals500=array(); // array to store index with <= 500
$i=0; // index for new aaray that will store keys that made up <= 500
$key1=1; //value to iterate the array defined above
for($key=1; $key <= count($values); $key++){
$sum = $sum + $values[$key]; // get sum of values
if($sum <= 500){ $Vals500[$i][]=$key; } //append all key of sum ==500
if($sum >= 500) { $i++; $key=$key1++; $sum=0; } //check sum then reintialize
//added bigger equal
}
echo count(max($Vals500)); // read out the biggest succession
?>
Thanks again to fas M !
Click Here or here you can see somehing
<?php //lets call your $BulkArray = $values;
$values=array( 1 => 100, 2 => 300, 3 => 100,
4 => 50, 5 => 50, 6 => 50, 7 => 50, 8 => 50,
9 => 500, 10 => 200, 11 => 100 );
$sum=0; // to sum up until 500
$Vals500=array(); // array to store index with <= 500
$i=0; // index for new aaray that will store keys that made up <= 500
$key1=1; //value to iterate the array defined above
//print_r($values); echo '<br/>';
for($key=1; $key <= count($values); $key++){
$sum = $sum + $values[$key]; // get sum of values
if($sum <= 500){ $Vals500[$i][]=$key; } //append all key of sum ==500
if($sum == 500) { $i++; $key=$key1++; $sum=0; } //check sum then reinitialize values
}
foreach($Vals500 as $val){} //search for second array with many indeces in $Vals500. NB: i fail this place
echo print_r($Vals500);
print 'the highest succession found is '; print_r($Vals500[2]); //
?>
In this question I got help to write a PHP function which gives a pyramid-like distribution:
function getRandomStrength($min, $max) {
$ln_low = log($min, M_E);
$ln_high = log($max, M_E);
$scale = $ln_high-$ln_low;
$rand = (mt_rand()/mt_getrandmax())*$scale+$ln_low;
$value = round(pow(M_E, $rand), 1);
return $value;
}
getRandomStrenth(1.1, 9.9);
// output could be: 1.4 or 8.3 or 9.8 or 7.2 or 2.9 or ...
When I run 50,000 iterations and check how often the numbers from 1 to 9 appear, I get the following list:
1 » 26%
2 » 19%
3 » 14%
4 » 10%
5 » 9%
6 » 7%
7 » 6%
8 » 6%
9 » 4%
This is what I wanted to have. But now I would like to adjust this function a bit. The smaller values should appear more often and the big values should appear less often - so that I get a list like this:
1 » 28%
2 » 20%
3 » 15%
4 » 11%
5 » 9%
6 » 6%
7 » 5%
8 » 5%
9 » 2%
As you can see, I just need a slight modification. But what can I change so that my function behaves as expected?
I tried several things (e.g. changing the base of the logarithm) but this did not change anything.
You can use pow on the random number.
$rand = pow( mt_rand()/mt_getrandmax(), 1.2 )*$scale+$ln_low;
By playing with the exponent value, you can get less or more small value.
Reducing the $scale of your function by a small (constant) amount seems to generate results pretty close to what you're looking for. You can achieve more accurate results by making this reduction of $scale a function of the randomly generated number from mt_rand(), which would require saving (mt_rand()/mt_getrandmax()) to a variable and performing some additional math on $scale.
Here are my tests, you can run it yourself: http://codepad.viper-7.com/ssblbQ
function getRandomStrength($min, $max)
{
$ln_low = log($min, M_E);
$ln_high = log($max, M_E);
$scale = $ln_high-$ln_low - .05; // Subtract a small constant, vary between .05 and .08
$rand = (mt_rand()/mt_getrandmax())*$scale+$ln_low;
$value = round(pow(M_E, $rand), 1);
return $value;
}
$values = array_fill(1, 9, 0);
for( $i = 0; $i < 50000; $i++)
{
$values[ intval( getRandomStrength(1.1, 9.9)) ]++;
}
for( $i = 1; $i <= 9; $i++)
{
$values[ $i] /= 500; // / 50000 * 100 to get a percent
}
var_dump( $values);
Output
Run #1 - Constant = 0.5
array(9) {
[1] => float(26.626) // Should be 28
[2] => float(19.464) // Should be 20
[3] => float(13.476) // Should be 15
[4] => float(10.41) // Should be 11
[5] => float(8.616) // Should be 9
[6] => float(7.198) // Should be 6
[7] => float(6.258) // Should be 5
[8] => float(5.52) // Should be 5
[9] => float(2.432) // Should be 2
}
Run #2 - Constant = 0.65
array(9) {
[1] => float(26.75) // Should be 28
[2] => float(19.466) // Should be 20
[3] => float(13.872) // Should be 15
[4] => float(10.562) // Should be 11
[5] => float(8.466) // Should be 9
[6] => float(7.222) // Should be 6
[7] => float(6.454) // Should be 5
[8] => float(5.554) // Should be 5
[9] => float(1.654) // Should be 2
}
Run #3 - Constant = 0.70
array(9) {
[1] => float(26.848) // Should be 28
[2] => float(19.476) // Should be 20
[3] => float(13.808) // Should be 15
[4] => float(10.764) // Should be 11
[5] => float(8.67) // Should be 9
[6] => float(7.148) // Should be 6
[7] => float(6.264) // Should be 5
[8] => float(5.576) // Should be 5
[9] => float(1.446) // Should be 2
}
For n in {0..1}, y=(x^n)-1, y will range from 0 to x-1. That curve is then easily mapped from 0 to some max value by multiplying by the range and dividing by (x-1). If you change the value x to something near one, the curve will be nearly linear, and at large values, the curve becomes more like a hockey-stick, but will still fall in the same range.
My initial sample value of three won't be precisely what you expressed, but you can adjust it to get the distribution curve you're looking for.
function getCustomStrength($min, $max, $x_val, $base) {
$logmax = $base-1;
$range = $max-$min;
return (pow($base,$x_val)-1)*($range/($base-1))+$min;
}
function getRandomStrength($min, $max) {
$rand = mt_rand()/mt_getrandmax();
$base = 3.0;
return getCustomStrength($min, $max, $rand, $base);
}
getRandomStrength(1.1, 9.9);
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) ]
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
)
$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)
{
$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;
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.
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.
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
)
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.
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;
}
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.
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.
This probably will solve your problem:
<?php print_r(array_rand(range(1,50), 5)); ?>
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);
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";
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
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;}
The best way to generate the unique random number is
<?php
echo md5(uniqid(mt_rand(), true).microtime(true));
?>