Loop in lines of true table - php

I have a problem about loop in line of true table. I need get all lines where only there are 3 positions with value equal 1, Look sample:
For a table with 4 elements exists 16 possibilities but I need just 4 of their. So I need to get the 4 positions without pass in all others positions:
[00002] 0-0-0-1
[00003] 0-0-1-0
[00004] 0-0-1-1
[00005] 0-1-0-0
[00006] 0-1-0-1
[00007] 0-1-1-0
[00008] 0-1-1-1 I want this
[00009] 1-0-0-0
[00010] 1-0-0-1
[00011] 1-0-1-0
[00012] 1-0-1-1 I want this
[00013] 1-1-0-0
[00014] 1-1-0-1 I want this
[00015] 1-1-1-0 I want this
[00016] 1-1-1-1
Look for 4 elements it's easy make a loop but you imagine a table with millions elements. Following is a code for ilustre my first thought:
$t1 = time();
echo "\n\n";
echo "################ Started in :" . date('d/m/Y H:i:s', $t1);
echo "\n\n";
$votesCount = 4;
$possibilities = pow(2, $votesCount);
for ($i = 0; $i < $possibilities; $i++) {
$binare = str_pad(decbin($i), $votesCount, 0, STR_PAD_LEFT);
$arrayBinare = str_split($binare);
$posVote = str_pad($i + 1, 5, 0, STR_PAD_LEFT);
$c = "[" . $posVote . '] ' . implode('-', $arrayBinare);
if (array_sum($arrayBinare) == 3) {
echo "<b>$c</b> I want this<br>";
continue;
}
echo "$c <br>";
}
$t2 = time();
echo "\n";
echo "################ Finished in:" . date('d/m/Y H:i:s', $t2);
echo "\n";
echo "################ Duraction: " . ($t2 - $t1) . ' seconds';
echo "\n";

A recursive solution looks like this:
function Enumerate(len, rem)
if rem = 0 then return [0]^len
if len < rem then return {}
if len = rem then return {[1]^rem}
return ({[0]} & Enumerate(len - 1, rem))
union
({[1]} & Enumerate(len - 1, rem - 1))
The notation [1]^rem means the vector of length rem containing only 1; the operator & returns all vectors obtained by concatenating vectors from the RHS to vectors in the LHS. This short-circuits when it detects that solutions can't be obtained or when there is only one possible solution, but you could remove this to print all permutations and just check them. Example execution:
Enumerate(4, 3) = {[0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0]}
4 < 3? no
4 = 3? no
[0] & Enumerate(3, 3) = [0] & [1,1,1] = [0,1,1,1]
3 = 0? no
3 < 3? no
3 = 3? yes, return [1,1,1]
[1] & Enumerate(3, 2) = [1] & ([0,1,1],[1,0,1],[1,1,0]| = {[1,0,1,1],[1,1,0,1],[1,1,1,0]}
2 = 0? no
3 < 2? no
3 = 3? no
[0] & Enumerate(2, 2) = [0] & [1,1] = [0,1,1]
2 = 0? no
2 < 2? no
2 = 2? yes, return [1,1]
[1] & Enumerate(2, 1) = [1] & {[0,1],[1,0]) = {[1,0,1],[1,1,0]}
1 = 0? no
2 < 1? no
2 = 1? no
[0] & Enumerate(1, 1) = [0] & [1] = [0,1]
1 = 0? no
1 < 1? no
1 = 1? yes, return [1]
[1] & Enumerate(1, 0) = [1] & [0] = [1,0]
0 = 0? yes, return [0]
If you want this to be iterative rather than recursive, add a stack data structure and manage the stack explicitly in a while loop while the stack's not empty.
If you want the position of each solution in the ordered space of all solutions - simply interpret the vector as the sequence of digits of a len-digit binary number and add one. So, [0,1,1,1] becomes (0111)b = (7)d + 1 = (8)d = 8.

With millions of rows, you definitely want to move the selection logic on the database side, or you'll have to make insane amounts of calculations on the PHP side, leading to potential performance & memory issues.
Assuming you have 4 vote columns storing 1 or 0:
SELECT *
FROM votes
WHERE (vote1 + vote2 + vote3 + vote4) = 3
And if you are storing booleans, you can cast it as an integer : WHERE CAST(vote1 AS SIGNED INTEGER) + ...

Related

Php equation: variable minus same rounded variable, possible?

I need to echo number(variable) in two ways and i need help with code for this equation.
Example:
Variable is 5003
First echo has to be: 5000 (rounded)
Second echo has to be just the rounded digits: 3
So i want to know if and how can i achieve this equation, im thinking among lines of: variable(5003) minus rounded variable(5000) equals 3
So that way if variable is lets say 15009
Fist will be 15000
Second will be 9
I hope this make sense, thank you for help
You should look into the roundPHP function:
You can have negative decimal points like this:
round(5003, -3); // returns 5000
round(15009, -3); // returns 15000
To figure out the difference you can do like this:
$input = 5003
$x = $input;
$y = round($input, -3);
$z = $x - $y; // z is now 3
PHP is not a mathematical language, so it cannot solve equations for you.
You can make a more general solution like this:
$inputs = [
5003,
15009,
55108,
102010
];
foreach ($inputs as $input) {
$decimals = floor(log10($input)) - 1;
$rounded = round($input, -1 * $decimals);
echo "$input - $rounded = " . ($input - $rounded) . PHP_EOL;
}
Outputs:
5003 - 5000 = 3
15009 - 15000 = 9
55108 - 55000 = 108
102010 - 100000 = 2010
Assuming that you want to round the last three digits:
$input = 5003;
$rounded = (int)(5003 / 1000) * 1000;
$rest = $input - $rounded;
echo($rounded . "\n" . $rest);
This results in:
5000
3

PHP - Get length of digits in a number

I would like to ask how I can get the length of digits in an Integer. For example:
$num = 245354;
$numlength = mb_strlen($num);
$numlength should be 6 in this example. Somehow I can't manage it to work?
Thanks
EDIT: The example code above --^ and its respective method mb_strlen(); works just fine.
Maybe:
$num = 245354;
$numlength = strlen((string)$num);
Accepted answer won't work with the big numbers. The better way to calculate the length of any number is to invoke floor(log10($num) + 1) with a check for 0.
$num = 12357;
echo $num !== 0 ? floor(log10($num) + 1) : 1; // prints 5
It has multiple advantages. It's faster, you don't do the casting of types, it works on big numbers, it works with different number systems like bin, hex, oct.
The equation does the logarithm with base 10 then makes the floor of it and adds 1.
This solution can work independently on the base, so if you want to calculate the length of binary or hex just change the base of the logarithm.
Working fiddle
The accepted solution presents a problem when evaluating negative numbers.
It works with a positive number:
$num = 245354;
$numlength = strlen((string)$num);
// Result: 6
But with a negative number, the (-) is added to the count:
$num = -245354;
$numlength = strlen((string)$num);
// Result: 7
Quick workaround:
$num = -245354;
$numlength = strlen((string)abs($num));
// Result: 6
More elegant way :)
ceil(log10($num));
You could also use some basic math!
$digits = (int)(log($num,10)+1)
<?php
$num = 123;
$num2 = 1234;
$num3 = 12345;
function digits($num){
return (int) (log($num, 10) + 1);
}
echo "\n $num: " . digits($num); // 123: 3
echo "\n $num2:" . digits($num2); // 1234: 4
echo "\n $num3:" . digits($num3); // 12345: 5
echo "\n";
Another way to find out the length of a number in digits would be to divide the integer part of the number to 10 until it becomes 0.
Example:
2021/10 = 202.1
202/10 = 20.2
20/10 = 2
2/10 = 0.2
Code:
function numberGetLength($number) {
$count = 0;
while (intval($number) > 0) {
$number = intval($number) / 10;
$count += 1;
}
return $count
}
Just using some version of (int)(log($num,10)+1) fails for 10, 100, 1000, etc. It counts the number 10 as 1 digit, 100 as two digits, etc. It also fails with 0 or any negative number.
If you must use math (and the number is non-negative), use:
$numlength = (int)(log($num+1, 10)+1);
Or for a math solution that counts the digits in positive OR negative numbers:
$numlength = ($num>=0) ? (int)(log($num+1, 10)+1) : (int)(log(1-$num, 10)+1);
But the strlen solution is just about as fast in PHP.
In PHP types are loosely set and guessed, if you want to see something as a string if it is an integer, float, and (i have not tried this) bool then #Gorjunav is the most correct answer.
Reset the variable as a string
$stringNum = (string) $num;
Then you can go anything string related you want with it! And vice-versa for changing a string to an int
$number = (int) $stringNum;
and so on...
count only integer value
`<?php
$n1 =12345;
$n2 =123454.55;
$n3 =12345564.557;
echo "The Number you Type: ".$n1."<br>";
$count = 0;
while ($n1 != 0)
{
$n1 = $n1 / 10;
$n1 = intval($n1);
++$count;
}
echo "The Digit in a Number: ".$count;
}
?>`
echo strlen((string) abs($num)); // using **abs** it'll work with negative integers as well
Tested in PHP 4.4.9 - 8.0.0
$array = array(-1, 0, -0, 1, 4, 9, 10, -10, 20, -20, 100, -100);
foreach( $array as $key => $num ){
echo $key."\t{$num}\t=>\t".($num !== 0 ? floor(log10(abs($num)) + 1) : 1)."\n";
}
/* Output:
0 -1 => 1
1 0 => 1
2 0 => 1
3 1 => 1
4 4 => 1
5 9 => 1
6 10 => 2
7 -10 => 2
8 20 => 2
9 -20 => 2
10 100 => 3
11 -100 => 3
*/
The following function work for either integers or floats (works with PHP7+):
function digitsCount($number): int
{
$number = abs($number);
$numberParts = explode(".", $number);
return
strlen($numberParts[0]) +
(strlen($numberParts[1] ?? 0));
}

backward sorting array in php

<?php
function apache($b) {
return $b;
}
$a = array(1, 2, 3, 4, 5, 6);
$num = "";
foreach ($a as $b) {
$num = apache($b) . $num ;
}
echo $num;
?>
When you write it like this the output is 654321, but if you write it like this:
$num = $num . apache($b);
the output would be 123456. I don't understand why the results are like that. Can someone explain this?
This isn't really hard to understand.
This line:
$num = apache($b) . $num;
add the currently selected number and appends the current value of $num to it. The result will be written to $num.
So this will happen:
$b. $num = $num
1 . "" = 1
2 . 1 = 21
3 . 21 = 321
4 . 321 = 4321
5 . 4321 = 54321
6 . 54321 = 654321
If you write
$num = $num . apache($b);
instead, you're adding the currently selected number behind $num:
$num .$b = $num
"" . 1 = 1
1 . 2 = 12
12 . 3 = 123
123 . 4 = 1234
1234 . 5 = 12345
12345 . 6 = 123456
one way you are appending to the string
the other way you are prepending to the string
which gives the effect of reversing it.
first way kind of looks like this
[1]
2[1]
3[21]
4[321]
5[4321]
6[54321]
the other way looks like this
[1]
[1]2
[12]3
[123]4
[1234]5
[12345]6
where the value outside the [] is the value being returned by your function and the value inside the [] is $num

php modulo and print_r of the result?

i wanted to make my own quarter-final draw for the champion's league (tomorrow, friday 16 of march) : i've got 2 questions : first the modulo does not work : it shows "another match" after every entry in the array, whereas i wanted it to be written every two matches (every 2 entries)...
Second question : is there a better way to "print" the result? like a print_r without the index and where i could say "add \n after each entry" ?
<body>
<?php
$array = array("real", "barça", "bayern", "apoel", "chelsea", "milan", "benfica", "marseille" );
$new = array();
$incr = count($array);
while($incr>0){
$random = rand(0, count($array));
if (!in_array($array[$random], $new)){
$new[] = $array[$random];
if ( (count($new) % 2) ){
$new[] = " -- another match : ";
}
$incr--;
}
}
print_r($new);
?>
<p>results</p>
</body>
Thanks for your help
Another option would be to shuffle the array then just pop off each of the elements
$array = array("real", "barça", "bayern", "apoel", "chelsea", "milan", "benfica", "marseille" );
shuffle($array);
while($a = array_pop($array)) {
echo $a." vs. ".array_pop($array)." <br />";
}
Sample output:
apoel vs. real
barça vs. milan
marseille vs. bayern
chelsea vs. benfica
The modulo is working perfectly:
The array starts empty.
You add an element to it.
The length is 1, so 1 % 2, so 1, so truthy, so you add -- another match to the array
So the length is now 2
Next iteration of the loop, you add another element to the array.
The length is now 3, so 3 % 2, so 1, so truthy, so you add -- another match
And so on. Whatever it is you're trying to do, it's not what you told the server to do.
What you should probably do is something like this:
$array = Array(........);
while($a = array_shift($array)) {
$random = rand(0,count($array)-1); // -1 is important!
echo $a." vs. ".$array[$random]."<br />";
unset($array[$random)];
// no need to realign keys since array_shift already does that
}
The modulus is working exactly as you're telling it to.
(count($new) % 2) ){
when count($new) = 1, 1 % 2 = 1, = true
when count($new) = 2, 2 % 2 = 0, = false
when count($new) = 3, 3 % 2 = 1, = true
when count($new) = 4, 4 % 2 = 0, = false
when count($new) = 5, 5 % 2 = 1, = true
when count($new) = 6, 6 % 2 = 0, = false

Finding the first integer not used in a collection of integers

After retrieving a list of integers used for ID in a mysql database, taking in that all the ID doesn't follow each other in each case (for example list could be [1,2,3,5,10,11,12,20,...]), what would be an more efficient way, aside from looping through all the integers, to find the lowest integer which isn't yet in the list (in our case, it would be 4, then 6 once 4 is attributed). Also it shouldn't be higher than 999.
This question give a mysql query, but I would like to do it in my php script, except if it would be more efficient.
This problem can be solved easily and efficiently using a binary search (which runs in O(log n), faster than a linear search, which is O(n)). The basic idea is that if and only if all the numbers are present up to a certain index, then list[index] = index + 1 (e.g. list[0] = 1, list[1] = 2, etc). This property can be used to determine whether the smallest missing number is before or after a certain element of the list, allowing for a binary search.
The implementation is simple (I don't know php, so here's pseudocode)
lower_bound = 0
upper_bound = length(list) - 1
index = floor((lower_bound + upper_bound) / 2)
while (lower_bound != upper_bound)
if(list[index] = index + 1) // missing number is after index
lower_bound = index + 1
index = floor((lower_bound + upper_bound) / 2)
else // missing number is at or before index
upper_bound = index
index = floor((lower_bound + upper_bound) / 2)
missing_number = upper_bound + 1 // add 1 because upper_bound is the index
And missing_number will be the smallest missing number, or if there are no missing numbers it will be length(list) + 1.
Or using recursion, which I hear is less efficient
first_missing_number(list, lower_bound, upper_bound) {
if(lower_bound = upper_bound) // found the first missing number
return upper_bound + 1 // add 1 because upper_bound is the index
index = floor((lower_bound + upper_bound) / 2)
if (list[index] = index + 1) // missing number is after index
first_missing_number(list, index + 1, upper_bound)
else // missing number is at or before index
first_missing_number(list, lower_bound, index)
}
In which case first_missing_number(list, 0, length(list) - 1) will return the first number missing from the list. If there are no numbers missing, it returns length(list) + 1.
I hope this helps!
upd: php version
function first_free($list) {
$lwr = 0;
$upr = count($list);
while ($lwr < $upr) {
$m = ($lwr + $upr) >> 1;
if($list[$m] == $m + 1)
$lwr = $m + 1;
else
$upr = $m;
}
return $upr + 1;
}
the most efficient way is the simple loop:
foreach($list as $n => $v)
if($v !== $n + 1) return $n + 1;
You can use the array_diff() function:
eg:
<?php
$array1 = array("a" => "1", "2", "3", "4");
$array2 = array("b" => "2", "4");
$result = array_diff($array1, $array2);
print_r($result);
?>
this will give you the missing items in the second array:
Array
(
[1] => 1
[2] => 3
)
Maybe this will be more efficient way:
$your_list = array(....);
$number_you_want = min(array_diff(range(1,999), $your_list));
Since you are limited to only 999 possible keys, I'd probably create a temporary table with all possible keys (i.e. 1-999), or even create a permanent table just for this purpose, then you can do sql like this:
SELECT key_value FROM temp_key_table WHERE key_value NOT IN (SELECT key FROM original_table ORDER BY key ASC) ORDER BY key_value ASC LIMIT 1
Not sure how practical this is, and a SQL guru could probably give you a better solution, but this should work in a pinch, rather than messing with this in PHP.
$array = array(1,2,3,5,10,11,12,20);
$missing = array_diff(range(min($array), max($array)), $array);
// First missing number is at $missing[0], next at $missing[1], etc.

Categories