I'm trying to create a generator for a lotto that I play very often.
The lotto is a 5 number draw, ranging from number 1-50 and the same number cannot appear again.
My current approach to do this is using array_rand() but after some reading I noticed that I should not use array_rand() for this purpose, instead I should be using random_int().
My current approach below:
$numbers = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50);
for ($i = 0; $i <= 4; $i++) {
$number = array_rand($numbers);
unset($numbers[$number]);
if ($number == 0) {
$number = array_rand($numbers);
unset($numbers[$number]);
}
$out1[] = array("<div class=\"number\">$number</div>");
}
As you can see above, this works and it generates 5 numbers without duplicating because I unset the number after it's been drawn.
My question is:
How can I do the same as above but using random_int()instead?
To clarify: Use random_int() to generate a random number but ensure that it doesnt generate the same number again in that run.
$numbers = array(); // Create an empty array
while (count($numbers) < 5) { // While less than 5 items in the array repeat the following
$random = random_int(1,50); // Generate a random number
if (!in_array($random, $numbers)) { // Check if the random number is already in the array, and if it is not then:
$numbers[] = $random; // add the random number to the array
}
}
foreach ($numbers as $n) { // Loop over your array and output with your added HTML
echo "<div class=\"number\">$n</div>";
}
Here's the way:
$out = [];
$used = [];
for ($i = 0; $i <= 4; $i++) {
do {
$randInt = random_int(1, 50);
} while (in_array($randInt, $used));
$used[] = $randInt;
$out[] = "<div class=\"number\">$randInt</div>";
}
Related
I'm trying to implement a radix sort in binary, because i want to check if the speed of bit shifting operations counterbalance the number of steps required.
My counting sort seems to work, but as soon as i have several passes for the radix sort, the result break.
Any help greatly appreciated.
/*
* bits is to store the value of the current digit for each number in the input array
*/
function countSort(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0);
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count
$count[1] = NB_ELEMS;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit] - 1] = $nb;
$count[$bit]--;
}
// Switch arrays
$arr = $output;
}
function radixSort(&$arr, $nb_digits) {
// Do counting sort for every binary digit
for($digit = 0; $digit < $nb_digits; $digit++) {
countSort($arr, $digit);
}
}
$tab = [4,3,12,8,7];
$max_value = max($tab);
$nb_digits = floor(log($max_value, 2)) + 1;
radixSort($tab, $nb_digits);
Ok, thanks to a friend, i found my problem : the counting sort implementation which i use stacks the same digit numbers using the counter as top index, and then decrementing it. And that's ok for counting sort (so one iteration), but it scrambles everything when you use it in radix sort (multiple counting sort iterations).
So i used instead a method in which you shift your counters one time right, which gives you for the n+1 digit your starting point, and then increment it.
And boom you're good to go.
function countSort2(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0); // output array
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count shifted
$count[1] = $count[0];
$count[0] = 0;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit]] = $nb;
$count[$bit]++;
}
// Switch arrays
$arr = $output;
}
I also made some tests (1M items, max value 1M, 100 iterations), and a method storing values instead of counting them, and merging thereafter seems twice as fast (function just after that). Anyway, both methods are far under native sort performance.
Any comment appreciated
function byDigitSortArrayMerge(&$arr, $digit) {
$output = array_fill(0, NB_ELEMS - 1, 0); // output array
$bits = array_fill(0, NB_ELEMS - 1, 0); // output array
$by_bit = [[], []];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$by_bit[$bit][] = $nb;
}
$arr = array_merge($by_bit[0], $by_bit[1]);
}
heres my code
while($x <= $num) {
$code = rand(1,666666).rand(2,88888888);
$INC = qry_run("Insert into ms_code2 (code) Values(".$code.")");
$x++;
}
the main problem is when this loop work sometimes it generate 14 number sometimes 10 and sometimes 12
I won't get into a discussion about how "random" we can ever really get, I am pretty sure this will generate a number random enough! :)
function randomNumber($length) {
$result = '';
for($i = 0; $i < $length; $i++) {
$result .= mt_rand(0, 9);
}
return $result;
}
..and of course then it's just echo randomNumber(14);
You can use this simple trick to generate (n) number of random numbers
function generateCode($limit){
$code = 0;
for($i = 0; $i < $limit; $i++) { $code .= mt_rand(0, 9); }
return $code;
}
echo generateCode(14);
This above function returns 14 random digits.
A simplest one could be this also, Here we are using array_map and range to iterate over callback function and maintain a string.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$string="";
array_map(function($value) use(&$string){
$string.=mt_rand(0, 9);
}, range(0,13));
echo $string;
I have this loop:
for ($i = 0; $i < 9; $i++) {
$random_number = rand(1, 9);
if (!in_array($section_one, $random_number)) {
array_push($section_one, rand(1, 9));
}
}
As you can see the if statement in the loop checks if the generated random number is already in the array called $section_one. The problem is that if the random number is in the array, a new random number should be generated. Doing this ones is easy, but it has to keep regenerating a random number until a unique one has been generated.
How can I do that?
$run = true;
$max = 9;
$section_one = [];
while ($run) {
$rand = rand(1,$max);
if(!in_array($rand, $section_one)){
array_push($section_one, $rand);
}
if(count($section_one) >= $max) $run = false;
}
The idea is running loop until $section_one got full unique numbers.
try this:
$section_one = array();
for ($i = 0; $i < 9; $i++) {
$random_number = rand(1, 9);
if (!in_array($random_number,$section_one)) {
array_push($section_one, $random_number);
}
}
var_dump($section_one);
I need to calculate from a given array the number that is equal or higher and closest to a given number in PHP. Example:
Number to fetch:
6.85505196
Array to calculate:
3.11350000
4.38350000
4.04610000
3.99410000
2.86135817
0.50000000
Only correct combination should be:
3.99410000 + 2.86135817 = 6.85545817
Can somebody help me? It's been 3 hours I'm getting mad!
UPDATE: I finally finished my code as following:
$arr = array(3.1135, 4.3835, 4.0461, 3.9941, 2.86135817, 0.5);
$fetch = 6.85505196;
$bestsum = get_fee($arr, $fetch);
print($bestsum);
function get_fee($arr, $fetch) {
$bestsum = 999999999;
$combo = array();
$result = array();
for ($i = 0; $i<count($arr); $i++) {
combinations($arr, $i+1, $combo);
}
foreach ($combo as $idx => $arr) {
$sum = 0;
foreach ($arr as $value) {
$result[$idx] += $value;
}
if ($result[$idx] >= $fetch && $result[$idx] < $bestsum) $bestsum = $result[$idx];
}
return $bestsum;
}
function combinations($arr, $level, &$combo, $curr = array()) {
for($j = 0; $j < count($arr); $j++) {
$new = array_merge($curr, array($arr[$j]));
if($level == 1) {
sort($new);
if (!in_array($new, $combo)) {
$combo[] = $new;
}
} else {
combinations($arr, $level - 1, $combo, $new);
}
}
}
I hope the following example might help you. Please try this
<?php
$array = array(
"3.11350000",
"4.38350000",
"4.04610000",
"3.99410000",
"2.86135817",
"0.50000000"
);
echo "<pre>";
print_r($array);// it will print your array
for($i=0; $i<count($array); $i++)
{
$j=$i+1;
for($j;$j<count($array); $j++)
{
$sum = $array[$i] + $array[$j];
// echo $array[$i]. " + ".$array[$j]." = ".$sum."<br>"; //this will display all the combination of sum
if($sum >= 6.85505196 && ($sum <= round(6.85505196)) )//change the condition according to your requirement
{
echo "The correct combinations are:<br/><br/>";
echo "<b>". $array[$i]. " + ".$array[$j]." = ".$sum."<b>";
echo "<br/>";
}
}
echo "<br/>";
}
?>
We will get the result as below
Array
(
[0] => 3.11350000
[1] => 4.38350000
[2] => 4.04610000
[3] => 3.99410000
[4] => 2.86135817
[5] => 0.50000000
)
The correct combinations are:
4.04610000 + 2.86135817 = 6.90745817
3.99410000 + 2.86135817 = 6.85545817
You should do it in two steps:
a. Work out (or look up) an algorithm to do the job.
b. Implement it.
You don't say what you've managed in the three hours you worked on this, so here's a "brute force" (read: dumb) algorithm that will do the job:
Use a variable that will keep your best sum so far. It can start out as zero:
$bestsum = 0;
Try all single numbers, then all sums of two numbers, then all sums of three numbers, etc.: Every time you find a number that meets your criteria and is better than the current $bestsum, set $bestsum to it. Also set a second variable, $summands, to an array of the numbers you used to get this result. (Otherwise you won't know how you got the solution). Whenever you find an even better solution, update both variables.
When you've tried every number combination, your two variables contain the best solution. Print them out.
That's all. It's guaranteed to work correctly, since it tries all possibilities. There are all sorts of details to fill in, but you can get to work and ask here for help with specific tasks if you get stuck.
Thank you all for your help!
My code is working pretty cool when is needed to fetch one or two numbers (addition) only. But can't figure out how to add more combinations up to the total count of elements in my given array.
I mean if there are, let's say, 8 numbers in my array I want to try all possible combinations (additions to each other) as well.
My actual code is:
$bestsum = 1000000;
for ($i = 0; $i < count($txinfo["vout"]); $i++) {
if ($txinfo["vout"][$i]["value"] >= $spent && $txinfo["vout"][$i]["value"] < $bestsum) {
$bestsum = $txinfo["vout"][$i]["value"];
}
}
for($i = 0; $i < count($txinfo["vout"]); $i++) {
$j = $i + 1;
for($j; $j < count($txinfo["vout"]); $j++) {
$sum = $txinfo["vout"][$i]["value"] + $txinfo["vout"][$j]["value"];
if($sum >= $spent && $sum < $bestsum) {
$bestsum = $sum;
}
}
}
$fee = bcsub($bestsum, $spent, 8);
print("Fee: ".$fee);
New updated code.
<?php
$x = 6.85505196;
$num = array(3.1135, 4.3835, 4.0461, 3.9941, 2.86135817, 0.5);
asort($num); //sort the array
$low = $num[0]; // lowest value in the array
$maxpossible = $x+$low; // this is the maximum possible answer, as we require the number that is equal or higher and closest to a given number
$num = array_values($num);
$iterations = $x/$num[0]; // possible combinations loop, to equate to the sum of the given number using the lowest number
$sum=$num;
$newsum = $sum;
$k=count($num);
for($j=0; $j<=$iterations; $j++){
$l = count($sum);
for($i=0; $i<$l; $i++){
$genSum = $sum[$j]+$sum[$i];
if($genSum <= $maxpossible){
$newsum[$k] = $genSum;
$k++;
}
}
$newsum = array_unique($newsum);
$newsum = array_values($newsum);
$k = count($newsum);
$sum = $newsum;
}
asort($newsum);
$newsum = array_values($newsum);
for($i=0; $i<count($newsum); $i++){
if($x<=$newsum[$i]){
echo "\nMaximum Possible Number = ".$newsum[$i];
break;
}
}
?>
I'm trying to find a way to replace any duplicated value but the only solution I have found so far is array_unique which doesn't really work for me as I need the duplicate to be replaced by another number which itself is not a duplicate.
function generate_random_numbers($rows, $delimiter)
{
$numbers = array();
for($i = 0; $i < $delimiter; $i++)
{
$numbers[$i] = rand(1, $rows);
if(in_array($i, $numbers))
{
$numbers[$i] = rand(1, $row);
}
}
return $numbers;
}
$numbers = generate_random_numbers(20, 10);
print_r($numbers);
would anyone help me out on this one please?
You can do this way easier and faster.
Just create an array for all possible numbers with range(). Then shuffle() the array and take an array_slice() as big as you want.
<?php
function generate_random_numbers($max, $amount) {
if($amount > $max)
return [];
$numbers = range(1, $max);
shuffle($numbers);
return array_slice($numbers, 0, $amount);
}
$numbers = generate_random_numbers(20, 10);
print_r($numbers);
?>
And if you want to get 490 unique elements from a range from 1 - 500, 10'000 times:
My version: ~ 0.7 secs
Your version: Order 2 birthday cakes, you will need them.
You are inserting a random number and then, if it is already in the array (which it MUST be because you just inserted it), you use a new random number, which might be a duplicate. So, you have to get a number that is not a duplicate:
do {
$num = rand(1,$rows);
} while(!in_array($num, $numbers));
Now, you know that $num is not in $numbers, so you can insert it:
$numbers[] = $num;
You were pretty close.
The if-clause needs to be a loop, to get new random number.
(Also your in_array was slightly wrong)
function generate_random_numbers($rows, $delimiter) {
$numbers = array();
for($i = 0; $i < $delimiter; $i++) {
do {
$number = rand(1, $rows);
}
while(in_array($number, $numbers));
$numbers[] = $number;
}
return $numbers;
}