Create dynamic for loop PHP function for all potential combinations - php

The code below will create an array for all possible combination that can occur when you have four different variables. The variables always need to equal 1. The for loops I have created work and I understand how to make this work for more variables, but can I make this dynamic? I need to have a function that has how many variables there are as a parameter. If there are three variables create the three forloops. If there are 10... create the 10 corresponding for loops to determine all possible combinations.
$anarray2 = array();
for( $a = 1; $a <= 97; $a++ ) {
for( $b = 1; $a + $b <=98 ; $b++ ) {
for( $c = 1; $a + $b + $c <= 99; $c++ ) {
$d = 100 - ( $a + $b + $c );
$var_1 = $a / 100;
$var_2 = $b / 100;
$var_3 = $c / 100;
$var_4 = $d / 100;
$anarray2[] = array( $var_1, $var_2, $var_3, $var_4 );
}
}
}
print_array( $anarray2 );

You're effectively looking to share out I identical items to N people in all of the different possible ways.
If there is one person (N==1), then there is only one way to do this - give that person all I items.
If there is more than one person (N>1), then we can consider how many items can be assigned to the first person, and then what the possible assignments are for the remaining N-1 people in each case.
This leads to a nice recursive solution. Firstly we solve the problem for N=1:
function assign($I, $N) {
$anarray = array();
if ($N == 1) {
$anarray[] = array($I);
} else {
// Coming up...
}
return $anarray;
}
Now we solve the problem for N=k (some constant) in terms of N=k-1 - that is, we solve the problem using the solution to a smaller problem. This will reach all the way back to the solution when N=1.
function assign($I, $N) {
$anarray = array();
if ($N == 1) {
$anarray[] = array($I);
} else {
for ($i = $I; $i < $I; $i++) {
foreach (assign($I - $i, $N - 1) as $subproblem) {
$anarray[] = array_merge(array($i), $subproblem);
}
}
}
return $anarray;
}
Something like that should do the job.

Related

PHP: How to distribute values to variables with equal probability?

Note to moderators: This is not a homework assignment.
I have the following example:
$points = 10;
$a = 0;
$b = 0;
$c = 0;
$d = 0;
I want to randomly distribute the points to the variables ($a,$b,$c,$d) until $points reach zero. So, expected random output after running some function/script should look like this:
$points = 0;// Must be zero
$a = 3;
$b = 1;
$c = 0;
$d = 6;
I'm thinking of doing a simple solution, which is the following:
while($points > 0) {
$points_taken = mt_rand(0, $points);
$points -= $points_taken;
$a += $points_taken;
$points_taken = mt_rand(0, $points);
$points -= $points_taken;
$b += $points_taken;
$points_taken = mt_rand(0, $points);
$points -= $points_taken;
$c += $points_taken;
$points_taken = mt_rand(0, $points);
$points -= $points_taken;
$d += $points_taken;
}
The function has 1 problem: $a has much more higher chance of taking more points (or even all points) because it's first in the list, while $d has much more higher chance of taking less points (or no points at all) because it's last in the list.
Question: How can I give all variables equal chance of distribution?
Note: It's fine if one of the variables took all the points.
You can use randomly select one of the variables from a range, and assign to it using a variable variable.
$vars = range('a','d');
while ($points) {
$points_taken = mt_rand(0, $points);
$points -= $points_taken;
${$vars[mt_rand(0, 3)]} += $points_taken;
}
Something like this?
$points = 10;
$a = 0;
$b = 0;
$c = 0;
$d = 0;
for($i=0; $i<$points; $i++) {
$rand = rand(1,4);
if($rand == 1) {
$a++;
} else if ($rand == 2) {
$b++;
} else if ($rand == 3) {
$c++;
} else if ($rand == 4) {
$d++;
}
}

How to find the common divisors of two numbers in PHP?

I use the following to find out the common divisors.
But in some case the count of divisors are not satisfied.
My Code :
$x = 66928;
$y = 66992;
$c_a = [];
$c_b = [];
$d = 1;
while ($d_a <= $x) {
if (is_int($x / $d)) $c_a[] = $d;
$d++;
}
$d = 1;
while ($d_b <= $y) {
if (is_int($y / $d)) $c_b[] = $d;
$d++;
}
echo count($c_a);
echo count($c_b);
// Output
$c_a = 20;
$c_b = 20;
Because, in some cases, it won't work.
Is this type of calculation is right ?
or any suggestions ?
As per asked in comment, to count the common factors of the two no. will be as like this.
<?php
$a = 66928;
$b = 66992;
$min = ($a < $b ) ? $a : $b;
$commomn_factors_count = 0;
for ($i = 1; $i < $min/2; $i++) {
if (($a%$i==0) && ($b%$i==0)) {
$commomn_factors_count++;
}
}
var_dump($commomn_factors_count);
You can you this code to get the fastest result to find the number of common divisors between two numbers:
// Function to calculate gcd of two numbers
function gcd($a, $b)
{
if ($a == 0)
return $b;
return gcd($b % $a, $a);
}
/* Function to calculate all common
* divisors of two given numbers
* a, b --> input integer numbers
*/
function commDiv($a, $b)
{
// find gcd of a, b
$n = gcd($a, $b);
// Count divisors of n.
$result = 0;
for ($i = 1; $i <= sqrt($n);
$i++)
{
// if 'i' is factor of n
if ($n % $i == 0)
{
// check if divisors
// are equal
if ($n / $i == $i)
$result += 1;
else
$result += 2;
}
}
return $result;
}
// Driver Code
$a = 10; $b = 15;
echo(commDiv($a, $b));

PHP-Trying to test for a 3-digit sequence of numbers within an array

I'm trying to determine if three sequential integers exist within an array. I've tested the code on several PHP sandbox sites, but as they don't allow the use of fgets, I've tested with an array that I have pre-filled with the 5 integers. The code works just fine under those circumstances, but fails miserably when run with an array filled by user-input. I'm not sure where the problem is, but any assistance would be greatly appreciated.
<?php
echo "Enter 5 Numbers:";
//{Write your code here
$arr = array();
for($i = 0; $i < 5; $i++){
$arr[$i] = trim(fgets(STDIN));
}
sort($arr);
function FindSeq($arr){
for($i = 0; $i < 3; $i++){
while($i < 3) {
$a = $i;
$b = $a + 1;
$c = $b + 1;
if(((($arr[$a]) + 1) === $arr[$b]) && ((($arr[$b]) + 1) === $arr[$c]) !== FALSE) {
exit("true");
}
else {
$i++;
}
}
}
}
FindSeq($arr);
echo "false";
?>
The lines are read in as strings, however you add + 1 which casts it to an integer. Then you use a strict comparison === with a string. Either use loose comparisons == or cast the values to an integer:
$arr[$i] = (int)trim(fgets(STDIN));
Here's a quick way to do this:
for($i = 2; $i=count($arr)-2; $i++)
if(($arr[$i-1] == $arr[$i]+1) && ($arr[$i+1] == $arr[$i] + 1))
return true;
return false;
The loop numbers account for your use of $arr[1] as the first element of the array. Something prettier would be more general.

PHP make array start from key / position

I want to tell my array to start from key position 2 and then loop through the entire array, including the values before key position 2. I just want to use one array and specify the key position I start looping from. For example, here I am using array_splice, but it does not do what I want it to, could you help me please?
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
foreach(array_slice($names, 2) as $name){
echo $name;
}
foreach(array_slice($names, 3) as $name){
echo $name;
}
If the keys are irrelevant, you can splice the array twice, and merge the resulting arrays, like this:
$names = array('Bill', 'Ben', 'Bert', 'Ernie');
$start = 2;
foreach( array_merge( array_slice($names, $start), array_slice( $names, 0, $start)) as $name){
echo $name;
}
You can see from the demo that this prints:
BertErnieBillBen
Alternatively, for efficiency, you can use two loops that are aware of wrapping around to the beginning, which will be more efficient since you are operating on the original array and not creating copies of it.
$start = 2;
for( $i = $start, $count = count( $names); $i < $count; $i++) {
echo $names[$i];
}
$i = 0;
while( $i < $start) {
echo $names[$i++];
}
You could also turn this into one single loop, and just encapsulate the logic for wrapping around inside the for.
$limit = 2; //so you can set your start index to an arbitrary number
$fn= function($a,$b) use ($limit){
if(($a < $limit && $b < $limit)
|| ($a >= $limit && $b >=$limit)) //$a and $b on the same side of $limit
return $a < $b ? -1 : ($a==$b ? 0 : 1);
if($a < $limit && $b > $limit) return 1; //because $a will always be considered greater
if($a >= $limit && $b < $limit) return -1; //because $b will always be considered greater
};
uksort($arr, $fn);
foreach($arr as $v) echo $v;

Why second passing php array element by reference generates wrong results?

I have this simple quicksort function (I got it from uncle "G")
function quicksort( &$list, $l , $r ) {
$i = $l;
$j = $r;
$tmp = $list[(int)( ($l+$r)/2 )];
do {
while( $list[$i] < $tmp )
$i++;
while( $tmp < $list[$j] )
$j--;
if( $i <= $j ) {
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
//_swp($list[$i],$list[$j]);
$i++;
$j--;
}
}while( $i <= $j );
if( $l < $j )
quicksort($list, $l, $j);
if( $i < $r )
quicksort($list, $i, $r);
return $list;
}
And I have this little function to swap two variables.
function _swp(&$a,&$b){
$a=$a+$b;
$b=$a-$b;
$a=$a-$b;
}
How come I can't use _swp($a,$b) in quicksort function instead of this lines?
$w = $list[$i];
$list[$i] = $list[$j];
$list[$j] = $w;
If I comment out these 3 lines of code and enter call to _swp function I got bad results...
Please explain.
Best regards
the unexpected behavior is probably the "random" occurence of zeros in the sorted list. This happens because there is a special case while swapping:
if( $i <= $j ) {
// swapping here using references!
_swp($list[$i],$list[$j]);
$i++;
$j--;
}
The problem is found directly in the condition for swapping itself: if $i==$j then there are two references to the same variable. Thus calling _swp($list[$i],$list[$j]); will firstly add both variables $a = $a + $b. Considering $a and $b actually access the same variable content, $a and $b will then have the same value. In the next step $b = $a - $b will then be zero as $a is equal to $b. The third operation will leave the result to 0.
An easy solution for this is inserting another condition:
if( $i <= $j ) {
// ensure $i to be truly smaller than $j
if( $i < $j ) {
_swp($list[$i],$list[$j]);
}
$i++;
$j--;
}
I hope this will help you.
Cheers,
Fabian

Categories