PHP if statements for numbers/digits greater than/less than - php

I have a little puzzle I'm trying to solve with no joy yet. I want to have a set of ifelse statements filter a number variable. Sort of like this.
If the assets are greater than 1500000, make the value down to a 6 digit number maximum using the numbers existing.
If the assets is smaller than 599999, make the value up to a 6 digit maximum using the numbers existing.
If the assets is between 599999 and 1500000, leave the variable alone and let it pass.
if ($assets > 1500000) {
$assets_calc = preg_match_all('/(\d{6})/', $assets_array, $matches);
}
elseif ($assets < 599999) {
$assets_calc = preg_match_all('/someregex here/', $assets_array, $matches);
} else {
$assets = $assets
}
Not sure if that is possible.

Not sure if this answers your question but are you looking to simply truncate digits of each value in the array?
if ($assets > 1500000)
{
foreach($assets_array as $k=>$v)
{
$assets_calc[$k] = (int)substr((string)$v, 0, 6);
}
}
// implement substring() in rest of code here

Related

PHP create function Palindrome

I really need your help. I have to create a function that takes 2 positive integers as its arguments and returns the numerical palindromes as an array of n numerical palindromes that come after the num, including num. Also, single-digit numbers are not considered numerical palindromes. So the outcome must be like this --> function(4,6) // returns [11,22,33,44]. Function(4, 6) it's an array that will take only 4 elements and the numerical palindromes must be greater than 6. Other examples are function (1, 75) // returns [77] and function (3, 100) // returns [101, 111, 121]
My code so far:
<?php
function createPalindrome($input)
{
$m = $input;
$palin = $input;
while ($m > 1) {
$d = intval($m % 10);
$palin = $palin * 10 + $d;
$m = intval($m / 10);
}
return $palin;
}
function generatePalindromes($x, $n)
{
$arr = [];
$i = 1;
while (($number = createPalindrome($i)) <= $n) {
$arr[] = $number;
$i++;
}
for($j = 0; $j < $x; $j++)
var_dump($arr[$j]);
}
generatePalindromes(4, 77);
The outcome is:
int(1)
int(22)
int(33)
int(44)
Had to modify this answer a fair bit once Giann49 expounded on his question in a comment reply.
This is not the cleanest or most precise way to do this for sure but it will principally function and hopefully help point you in the right direction logically.
function findExceedingPalindromes($palindromeLimit,$startingPoint){
$palindromesFound = 0; //Set an initial counter for number of palindromes found so far.
$palindromeSet = []; //Create an array to contain all the palindromes.
if($palindromeLimit <= 0 || $startingPoint <= 0){ //Both integers need to be positive as stated.
return false; //If they aren't return false. You can return whatever you want to halt execution of the function. This is just an easy example.
}
if($startingPoint < 10){
$startingPoint = 10; //Since single digits aren't valid if the starting number if less than 10 kick it up to 10.
}
while($palindromesFound <= $palindromeLimit){
$startingPoint++; //Since the first palindrome must exceed the starting point increment it up once at the top of the loop.
$reverseNumber = strrev($startingPoint); //reverse the current number.
if($startingPoint === $reverseNumber){
array_push($palindromeSet,$startingPoint);
$palindomresFound++; //If we find a palindome move the number found 1 higher.
}
}
return $palindromeSet;
}
As an explanation.
The first argument is the number of palindromes to generate. The second argument is the number we want to start palindrome generation at then work up from there.
We create two variables. One is to track how many palindromes have been found. The other is an empty array to insert found palindromes into.
You say the two numbers must be positive integers so if they are anything less than 1 we'll want to exit the function. (optional)
You say single digits don't count so if the starting point is less than 10 we'll just move it up to 10 for starters. (optional)
Now we'll start a while loop. While the number of palindromes is less than the number we want to find the loop will keep running.
We add 1 to the starting point right out of the gate because we want to first palindrome to be higher than the starting point if it already is one. As in if 11 is the number set as the point to start searching we want to look at 11 + 1 for starters. (optional)
To check if a number of a palindrome we want to simply reverse it's string. If the strings are the same forward and back obviously it matches the definition of a palindrome. So we'll add that number into the set of found palindromes and move the number found 1 digit higher.
Once the requested number of palindromes are found we'll break the while loop and return the array of what was found.

PHP Simple Math Results in Unexpected Result

I have two variables in a PHP program for billing statements, $charges and $payments.
$charges is the total amount due before any payments. $payments is the total amount received.
I calculate the balance due like so:
$balance_due = $charges-$payments;
Simple, except I am getting the following result:
$balance_due has -9.0949470177293E-13 for a value (expecting 0).
Both $charges and $payments have a value of 5511.53.
When I var_dump($charges) and var_dump($payments) they both show: float(5511.53)
This code (and === ):
if($charges == $payments){
error_log('they are the same');
}else{
error_log('they are not the same');
}
both result in false.
If I hard code: $charges = $payments = 5511.53; and run it then $balance_due = 0 as expected.
I am confused. What am I missing?
EDIT NOTES
I was able to use a user contributed function by Nitrogen found on the BC Math Functions page that was suggested I look at in order to come up with the following solution:
if(Comp($charges, $payments)===0){
$balance_due = 0;
}else{
$balance_due = ( $charges - $payments );
}
function Comp($Num1,$Num2,$Scale=null) {
// check if they're valid positive numbers, extract the whole numbers and decimals
if(!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num1,$Tmp1)||
!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num2,$Tmp2)) return('0');
// remove leading zeroes from whole numbers
$Num1=ltrim($Tmp1[1],'0');
$Num2=ltrim($Tmp2[1],'0');
// first, we can just check the lengths of the numbers, this can help save processing time
// if $Num1 is longer than $Num2, return 1.. vice versa with the next step.
if(strlen($Num1)>strlen($Num2)) return(1);
else {
if(strlen($Num1)<strlen($Num2)) return(-1);
// if the two numbers are of equal length, we check digit-by-digit
else {
// remove ending zeroes from decimals and remove point
$Dec1=isset($Tmp1[2])?rtrim(substr($Tmp1[2],1),'0'):'';
$Dec2=isset($Tmp2[2])?rtrim(substr($Tmp2[2],1),'0'):'';
// if the user defined $Scale, then make sure we use that only
if($Scale!=null) {
$Dec1=substr($Dec1,0,$Scale);
$Dec2=substr($Dec2,0,$Scale);
}
// calculate the longest length of decimals
$DLen=max(strlen($Dec1),strlen($Dec2));
// append the padded decimals onto the end of the whole numbers
$Num1.=str_pad($Dec1,$DLen,'0');
$Num2.=str_pad($Dec2,$DLen,'0');
// check digit-by-digit, if they have a difference, return 1 or -1 (greater/lower than)
for($i=0;$i<strlen($Num1);$i++) {
if((int)$Num1{$i}>(int)$Num2{$i}) return(1);
else
if((int)$Num1{$i}<(int)$Num2{$i}) return(-1);
}
// if the two numbers have no difference (they're the same).. return 0
return(0);
}
}
}
That solution worked for me. The answer provided by imtheman below also works and seems more efficient so I am going to use that one instead. Is there any reason not to use one or the other of these?
The way I solved this problem when I ran into it was using php's number_format(). From php documentation:
string number_format(float $number [, int $decimals = 0 ])
So what I would do is this:
$balance_due = number_format($charges-$payments, 2);
And that should solve your problem.
Note: number_format() will return a string, so to compare it you must use == (not ===) or cast it back into a (float) before comparison.

PHP List all possible 6-digit numbers with specific digits [duplicate]

This question already has answers here:
Algorithm to get all possible string combinations from array up to certain length
(12 answers)
Closed 9 years ago.
How could I generate every possible number of a given amount of digits and using specific digits?
So basically, I would like to have a 6 digit number for example using only the numbers ['1','2','3']. I've tried a few methods of recursion, however, I can't get it to work correctly due to my other complication, which is adding a separator of "|" in between each 2 digits. So the list would be like so:
11|11|11
11|11|12
11|11|13
11|11|21
11|11|22
11|11|23
etc..
Would be appreciated if someone could point me in the right direction.
Also a way of dumping each of the combinations into my MySQL database would be great.
Here is a much updated answer (originally updated from this answer]1) to your question:
function findPermutations($arr, $arrLen, $size, $perArr = array(), $pos = 0, &$found = array()) {
if ($size==$pos) { //if $pos reach $size then we have found one permutation
$found[] = vsprintf("%s%s|%s%s|%s%s", $perArr);
return;
}
for ($i=0; $i<$arrLen; $i++) {
$perArr[$pos] = $arr[$i]; //put i'th char in current position
//The recursive call that move to next position with $pos+1
findPermutations($arr, $arrLen, $size, $perArr, $pos+1, $found);
}
return $found;
}
$permutations = array();
$letters = array('1','2','3');
$max_length = 6;
$permutations = findPermutations($letters, count($letters), $max_length);
for($i = 0; $i < count($permutations); $i++) {
print ($permutations[$i].'<br/>');
}
Here is what I'm doing. I'm passing in an empty array called $permutations by reference, and as I find new permutations, I'm appending them to it. When the function findPermutations() is complete, I end up with an array of all permutation, that I can iterate over or insert. To get the formatting I'm using vsprintf, that lets me pass an array of data and apply a format (in this case %s%s|%s%s|%s%s). Lastly I'm using default argument values to make calling this function cleaner.
you mean something like this?
$letters='123'; // add other numbers
for($i=0;$i<3;$i++) { //generate 3 pairs
$pairs[]=$letters[rand(0,2)] . $letters[rand(0,2)];
}
//then join them together
$finalstring=implode('-',$pairs);

generating an sequential five digit alphanumerical ID

General Overview:
The function below spits out a random ID. I'm using this to provide a confirmation alias to identify a record. However, I've had to check for collision(however unlikely), because we are only using a five digit length. With the allowed characters listed below, it comes out to about 33 million plus combinations. Eventually we will get to five million or so records so collision becomes an issue.
The Problem:
Checking for dupe aliases is inefficient and resource heavy. Five million records is a lot to search through. Especially when this search is being conducted concurrently by different users.
My Question:
Is there a way to 'auto increment' the combinations allowed by this function? Meaning I only have to search for the last record's alias and move on to the next combination?
Acknowledged Limitations:
I realize the code would be vastly different than the function below. I also realize that mysql has an auto increment feature for numerical IDs, but the project is requiring a five digit alias with the allowed characters of '23456789ABCDEFGHJKLMNPQRSTUVWXYZ'. My hands are tied on that issue.
My Current Function:
public function random_id_gen($length)
{
$characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$max = strlen($characters) - 1;
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= $characters[mt_rand(0, $max)];
}
return $string;
}
Why not just create a unique index on the alias column?
CREATE UNIQUE INDEX uniq_alias ON MyTable(alias);
at which point you can try your insert/update and if it returns an error, generate a new alias and try again.
What you really need to do is convert from base 10 to base strlen($characters).
PHP comes with a built in base_convert function, but it doesn't do exactly what you want as it will use the numbers zero, one and the letter 'o', which you don't have in your version. So you'll need a function to map the values from base_convert from/to your values:
function map_basing($number, $from_characters, $to_characters) {
if ( strlen($from_characters) != strlen($to_characters)) {
// ERROR!
}
$mapped = '';
foreach( $ch in $number ) {
$pos = strpos($from_characters, $ch);
if ( $pos !== false ) {
$mapped .= $to_characters[$pos];
} else {
// ERROR!
}
}
return $mapped;
}
Now that you have that:
public function next_id($last_id)
{
$my_characters = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
$std_characters ='0123456789abcdefghijklmnopqrstuv';
// Map from your basing to the standard basing.
$mapped = map_basing($last_id, $my_characters, $std_characters);
// Convert to base 10 integer and increment.
$intval = base_convert($mapped, strlen($my_characters), 10);
$intval++;
// Convert to standard basing, then to our custom basing.
$newval_std = base_convert($intval, 10, strlen($my_characters));
$newval = map_basing($newval_std, $std_characters, $my_characters);
return $newval;
}
Might be some syntax errors in there, but you should get the gist of it.
You could roll your own auto-increment. It would probably be fairly inefficient though as you'd have to figure out where in the process your increment was. For instance, if you assigned the position in your random string as an integer and started with (0)(0)(0)(0)(0) that would equate to 22222 as the ID. Then to get the next one, just increment the last value to (0)(0)(0)(0)(1) which would translate into 22223. If the last one gets to your string length, then make it 0 and increment the second to last, etc... It's not exactly random, but it would be incremented and unique.

How to get a random value from 1~N but excluding several specific values in PHP?

rand(1,N) but excluding array(a,b,c,..),
is there already a built-in function that I don't know or do I have to implement it myself(how?) ?
UPDATE
The qualified solution should have gold performance whether the size of the excluded array is big or not.
No built-in function, but you could do this:
function randWithout($from, $to, array $exceptions) {
sort($exceptions); // lets us use break; in the foreach reliably
$number = rand($from, $to - count($exceptions)); // or mt_rand()
foreach ($exceptions as $exception) {
if ($number >= $exception) {
$number++; // make up for the gap
} else /*if ($number < $exception)*/ {
break;
}
}
return $number;
}
That's off the top of my head, so it could use polishing - but at least you can't end up in an infinite-loop scenario, even hypothetically.
Note: The function breaks if $exceptions exhausts your range - e.g. calling randWithout(1, 2, array(1,2)) or randWithout(1, 2, array(0,1,2,3)) will not yield anything sensible (obviously), but in that case, the returned number will be outside the $from-$to range, so it's easy to catch.
If $exceptions is guaranteed to be sorted already, sort($exceptions); can be removed.
Eye-candy: Somewhat minimalistic visualisation of the algorithm.
I don't think there's such a function built-in ; you'll probably have to code it yourself.
To code this, you have two solutions :
Use a loop, to call rand() or mt_rand() until it returns a correct value
which means calling rand() several times, in the worst case
but this should work OK if N is big, and you don't have many forbidden values.
Build an array that contains only legal values
And use array_rand to pick one value from it
which will work fine if N is small
Depending on exactly what you need, and why, this approach might be an interesting alternative.
$numbers = array_diff(range(1, N), array(a, b, c));
// Either (not a real answer, but could be useful, depending on your circumstances)
shuffle($numbers); // $numbers is now a randomly-sorted array containing all the numbers that interest you
// Or:
$x = $numbers[array_rand($numbers)]; // $x is now a random number selected from the set of numbers you're interested in
So, if you don't need to generate the set of potential numbers each time, but are generating the set once and then picking a bunch of random number from the same set, this could be a good way to go.
The simplest way...
<?php
function rand_except($min, $max, $excepting = array()) {
$num = mt_rand($min, $max);
return in_array($num, $excepting) ? rand_except($min, $max, $excepting) : $num;
}
?>
What you need to do is calculate an array of skipped locations so you can pick a random position in a continuous array of length M = N - #of exceptions and easily map it back to the original array with holes. This will require time and space equal to the skipped array. I don't know php from a hole in the ground so forgive the textual semi-psudo code example.
Make a new array Offset[] the same length as the Exceptions array.
in Offset[i] store the first index in the imagined non-holey array that would have skipped i elements in the original array.
Now to pick a random element. Select a random number, r, in 0..M the number of remaining elements.
Find i such that Offset[i] <= r < Offest[i+i] this is easy with a binary search
Return r + i
Now, that is just a sketch you will need to deal with the ends of the arrays and if things are indexed form 0 or 1 and all that jazz. If you are clever you can actually compute the Offset array on the fly from the original, it is a bit less clear that way though.
Maybe its too late for answer, but I found this piece of code somewhere in my mind when trying to get random data from Database based on random ID excluding some number.
$excludedData = array(); // This is your excluded number
$maxVal = $this->db->count_all_results("game_pertanyaan"); // Get the maximum number based on my database
$randomNum = rand(1, $maxVal); // Make first initiation, I think you can put this directly in the while > in_array paramater, seems working as well, it's up to you
while (in_array($randomNum, $excludedData)) {
$randomNum = rand(1, $maxVal);
}
$randomNum; //Your random number excluding some number you choose
This is the fastest & best performance way to do it :
$all = range($Min,$Max);
$diff = array_diff($all,$Exclude);
shuffle($diff );
$data = array_slice($diff,0,$quantity);

Categories