Check value within range or not php - php

I want to check value with in range or not suppose if I have range D1 to D40 and if I enter D20 then it returns value with in range.
I check several solution but this are for only integer not for both string and integer.
EDIT
Range will be dynamic like AA20 to AA30 or like AC10D to AC30D

You can write something simpler like this...
$arr = range(1,40); //<--- Creating a range of 1 to 40 elements..
array_walk($arr,function (&$v){ $v = 'D'.$v;}); //<--- Concatenating D to all the elements..
echo in_array('D20',$arr) ? 'Found' : 'Not Found'; //<-- The search part.
Demonstration

First, you should remove the letter D from your string variable, like this:
// This is your first variable:
$rang1="D5";
// This is your second rang variable:
$rang2="D20";
$rang1=str_replace("D","",$rang1);
$rang2=str_replace("D","",$rang2);
$rang=$rang2-$rang1;
echo $rang;
Or if your variable looks like this:
$rang="D5 TO D20";
you can use the following:
$rang="D5 TO D20";
$rang=explode(" TO ",$rang);
$rang1=rang[0];
$rang2=rang[1];
$rang1=str_replace("D","",$rang1);
$rang2=str_replace("D","",$rang2);
$rang=$rang2-$rang1;
echo $rang;

// 1. build up array of valid entries
$prefix = "D";
$rangeArray = array();
for($i = 1; $i <= 40; $i++) {
$rangeArray[] = $prefix . $i;
}
...
// 2. check against that array:
$inRange = in_array($needle, $rangeArray); // boolean
To get the position in the range:
$pos = array_search($needle, $rangeArray); // integer or false if not found
Where $needle would be your input value.

The following code will work with ranges with different letter in the beginning like A10 to B30 (assuming A20 is in that range, but A40 is not):
$min = "A10";
$max = "B30";
$test = "A20";
$min_ascii = chr($min[0]);
$max_ascii = chr($max[0]);
$test_ascii = chr($max[0]);
$min_number = substr($min, 1);
$max_number = substr($max, 1);
$test_number = substr($test, 1);
if ($min_ascii <= $test_ascii and $test_ascii <= $max_ascii
and $min_number <= $test_number and $test_number <= $max_number)
{
echo "$test is in the range from $min to $max";
}

Related

Pairwise function different calculation

i have this function:
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
for ($i = 0; $i < $n; $i++)
{
// absolute difference between
// consecutive numbers
$diff = abs($arry[$i] - $arry[$i + 1]);
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);
The problem are that im not expecting this output
becouse first number of array (20) is my commission
and the other numbers are my parents commission (10,10,50).
So basically i need to output like this: (0,0,30)
becouse i take 20 of commission,
first parent not take nothing becouse are less of my commission (10)
second parent not take nothing becouse are less of my commission (10)
and only last parent take 30 becouse are greater than my commission (50 - 20 my commission).
Thanks in advance
Since your first element of the array is your commission and the others are the the commissions of parents, and since it seems that you don't want to include your commission in the result array, you can do something like this:
function pairwiseDifference($arry)
{
$n = count($arry);
$diff = 0;
$result = array();
$myComm = $arry[0]; // your commision
for ($i = 1; $i < $n; $i++)
{
$diff = 0; // set $diff to 0 as default
if($myComm < $arry[$i]) // if your commision < parent commision
$diff = $arry[$i] - $myComm;
echo $diff." ";
array_push($result, $diff);
}
return $result;
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
$diffArray = pairwiseDifference($arry);
echo $diffArray[0]; // prints 0
echo $diffArray[1]; // prints 0
echo $diffArray[2]; // prinst 30
To tweak the logic according to your code, there would be only 3 modifications.
Create a $max variable and assign it the value of $arry[0].
Make difference as 0 if current max is greater than current one, else take the difference.
Calculate the new max again using max() function.
Snippet:
<?php
function pairwiseDifference($arry)
{
$n = count($arry) - 1; // you can add the -1 here
$diff = 0;
$result = array();
$max = $arry[0]; // new addition
for ($i = 1; $i <= $n; $i++) // new modification <= n instead of < n
{
// absolute difference between
// consecutive numbers
$diff = $max < $arry[$i] ? $arry[$i] - $max : 0; // new modification
$max = max($max, $arry[$i]); // new modification
echo $diff." ";
array_push($result, $diff); // use array_push() to add new items to an array
}
return $result; // return the result array
}
$arry = array(20,10,10,50);
echo "<br> Percent of commisions are: ";
// this echos 10,0,40 and assigns whatever your function returns
// to the variable $diffArray
$diffArray = pairwiseDifference($arry);

Round number in php depending on the value

I know the following code will remove the numbers are the point.
round($number);
I want to round the numbers as follows
if number is 20.123
I want result 20,
If number is 20.567
I want result 21
Means if value is below .5 , it should remove that value.
If value if .5 or above it should round up.
How ?
Anyone help ?
round($number) will do what you want:
round(20.156); // 20
round(20.651); // 21
Live example
I am sure it's working well.
<?php
$var = 22.443;
$var = number_format($var, 0, '.', '');
echo $var;
?>
function get_decimal_num($number){
$num = explode('.', $number);
return $num[1];
}
$num = 10.5 ; // for example
$val = get_decimal_num($num);
if($val >= 5)
{
$value = (int) $num;
echo $value = $value + 1;
}
if($val < 5)
{
echo $num;
}
Plese check it...
Try this:
use the ceil, floor, explode and substr function to achieve you value.
$num = "20.123";
$arr = explode(".", $num);
if(substr($arr[1], 0, 1) >= 5){
$num = ceil($num);
}else{
$num = floor($num);
}
echo $num;
Result:
20
Also you can use the round function.
round(20.156); // 20
round(20.651); // 21

php loop with letters without using an array of letters

I have an php code that writes an excel file with a variable number of columns. Each 4 rows, on the 5th I want to put the total of the four rows above, per column.
My issue is on how to write the formula in terms of columns.
My code is this one:
$col_index=20;
$i=20;
for($anno = $annoMin; $anno<=$annoMax; $anno++){
for($mese = 1; $mese <= 12; $mese++){
$string = "=$i$v+$i$q-$i$z-$i$t";
$ews->setCellValueByColumnAndRow($col_index,$k,$string);
$col_index=$col_index+1;
$i=$i+1;
}
}
In $string I need to put the column letter instead of $i. $v,$q,$z and $t are the reference to the rows and are ok. In other words $string should be evaluated to:
$string = "=U5+U3-U2-U4";
during the first for loop,
$string = "=V5+V3-V2-V4";
in the second and so on.
I know I can build an array of columns letter and use that $i reference to get my goal but I'm sure there is a better approach. I am using php 5.5 btw
The other option is to write the formula with the R1C1 notation but I'm pretty sure I cannot have the standard and the R1C1 notation in an excel sheet at the same time
You can increment a string variable. I think this is the most efficient way to do what you need (if I understood it right).
$ch = "a";
++$ch;
echo $ch; //prints "b"
Knowing this you can build a loop to update the value as you need.
This works very good for Excel because:
$ch = "z";
++$ch;
echo $ch; //prints aa
I'm just concentrating on the column letter as that seems to be what you're asking. Use the ASCII code of the letter and increment it, then convert it to the character:
$col_index = 20;
$i = ord('U'); // 85
for($anno = $annoMin; $anno<=$annoMax; $anno++){
for($mese = 1; $mese <= 12; $mese++){
$c = chr($i);
$string = "=$c$v+$c$q-$c$z-$c$t"; // $i will be U then V etc...
$ews->setCellValueByColumnAndRow($col_index,$k,$string);
$col_index = $col_index+1;
$i++;
}
}
If you need to keep $i starting at 20 and incrementing then just add 65:
$col_index = 20;
$i = 20;
for($anno = $annoMin; $anno<=$annoMax; $anno++){
for($mese = 1; $mese <= 12; $mese++){
$c = chr($i + 65);
$string = "=$c$v+$c$q-$c$z-$c$t"; // $i will be U then V etc...
$ews->setCellValueByColumnAndRow($col_index,$k,$string);
$col_index = $col_index+1;
$i++;
}
}

Counting possibilities in a char. combination using a consecutive repetition criterion

In PHP, given
the final string length
the range of characters it can use
min consecutive repetition count possible
how can you calculate the number of matches that fits these criteria?To draw a better picture…
$range = array('a','b','c');
$length = 2; // looking for 2 digit results
$minRep = 2; // with >=2 consecutive characters
// aa,bb,cc = 3 possibilities
another one:
$range = array('a','b','c');
$length = 3; // looking for 3 digit results
$minRep = 2; // with >=2 consecutive characters
// aaa,aab,aac,baa,caa
// bbb,bba,bbc,abb,cbb
// ccc,cca,ccb,acc,bcc
// 5 + 5 + 5 = 15 possibilities
// note that combos like aa,bb,cc are not included
// because their length is smaller than $length
last one:
$range = array('a','b','c');
$length = 3; // looking for 3 digit results
$minRep = 3; // with >=3 consecutive characters
// aaa,bbb,ccc = 3 possibilities
So basically, in the 2nd example the 3rd criterion made it catch e.g. [aa]b in aab because a was repeating consecutively more than once, whereas [a]b[a] wouldn't be a match because those a's are separate.
Needless to say, none of the variables is static.
Got it. All credit to leonbloy #mathexchange.com.
/* The main function computes the number of words that do NOT contain
* a character repetition of length $minRep (or more). */
function countStrings($rangeLength, $length, $minRep, &$results = array())
{
if (!isset($results[$length]))
{
$b = 0;
if ($length < $minRep)
$b = pow($rangeLength, $length);
else
{
for ($i = 1; $i < $minRep; $i++)
$b += countStrings($rangeLength, $length - $i, $minRep, $results);
$b *= $rangeLength - 1;
}
$results[$length] = $b;
}
return $results[$length];
}
/* This one answers directly the question. */
function printNumStringsRep($rangeLength, $length, $minRep)
{
$n = (pow($rangeLength, $length)
- countStrings($rangeLength, $length, $minRep));
echo "Size of alphabet : $rangeLength<br/>"
. "Size of string : $length<br/>"
. "Minimal repetition : $minRep<br/>"
. "<strong>Number of words : $n</strong>";
}
/* Prints :
*
Size of alphabet : 3
Size of string : 3
Minimal repetition : 2
Number of words : 15
*
*/
printNumStringsRep(3, 3, 2);
I think it is best to handle this with math.
$range = array('a','b','c');
$length = 3; // looking for 3 digit results
$minRep = 2; // with >=2 consecutive characters
$rangeLength = count($range);
$count = (pow($rangeLength,$length-$minRep+1) * ($length-$minRep+1)) - ($rangeLength * ($length-$minRep)); // is the result
Now, $count is getting true result for three situation. But it may not be general formula and need to improve.
Try to explain it:
pow($rangeLength,$length-$minRep+1)
in this, we count repetitive characters like as one. For instance, in second example that you gave, we think in aab, aa is a one character. Because, two characters need to change together. We think now there is two character like xy. So there is same possibilities for both character a, b, and c namely 3 ($rangeLength) possible value for two characters($length-$minRep+1). So 3^2=9 is possible situations for second example.
We calculate 9 is for just xy not yx. For this, we multiply length of xy ($length-$minRep+1). And then we have 18.
It can be seemed that we calculated the result, but there is a repeat in our calculation. We didn't reckon with this situation: xy => aaa and yx => aaa. For this, we calculate and substract repeated results
- ($rangeLength * ($length-$minRep))
So after this, we get result.
As i said begining of the description, this formula may need to improve.
With Math, work becomes really complex. But, there is always a way, even not beautiful as much as Math. We can create all possible strings with php and control them with regexp like below:
$range = array('a','b','c');
$length = 3;
$minRep = 2;
$rangeLength = count($range);
$createdStrings = array();
$matchedStrings = array();
function calcIndex(){
global $range;
global $length;
global $rangeLength;
static $ret;
$addTrigger = false;
// initial values
if(is_null($ret)){
$ret = array_fill(0, $length, 0);
return $ret;
}
for($i=$length-1;$i>=0;$i--){
if($ret[$i] == ($rangeLength-1)) {
if($i==0) return false;
$ret[$i] = 0;
}
else {
$ret[$i]++;
break;
}
}
return $ret;
}
function createPattern()
{
global $minRep;
$patt = '/(.)\\1{'.($minRep-1).'}/';
return $patt;
}
$pattern = createPattern();
while(1)
{
$index = calcIndex();
if($index === false) break;
$string = '';
for($i=0;$i<$length;$i++)
{
$string .= $range[$index[$i]];
}
if(!in_array($string, $createdStrings)){
$createdStrings[] = $string;
if(preg_match($pattern, $string)){
$matchedStrings[] = $string;
}
}
}
echo count($createdStrings).' is created:';
var_dump($createdStrings);
echo count($matchedStrings).'strings is matched:';
var_dump($matchedStrings);

How to reduce lists of ranges?

Given a list of ranges ie: 1-3,5,6-4,31,9,19,10,25-20
how can i reduce it to 1-6,9-10,19-25,31 ?
Here is what i've done so far, it seems a little bit complicated, so
is there any simpler/clever method to do this.
$in = '1-3,5,6-4,31,9,19,10,25-20';
// Explode the list in ranges
$rs = explode(',', $in);
$tmp = array();
// for each range of the list
foreach($rs as $r) {
// find the start and end date of the range
if (preg_match('/(\d+)-(\d+)/', $r, $m)) {
$start = $m[1];
$end = $m[2];
} else {
// If only one date
$start = $end = $r;
}
// flag each date in an array
foreach(range($start,$end) as $i) {
$tmp[$i] = 1;
}
}
$str = '';
$prev = 999;
// for each date of a month (1-31)
for($i=1; $i<32; $i++) {
// is this date flaged ?
if (isset($tmp[$i])) {
// is output string empty ?
if ($str == '') {
$str = $i;
} else {
// if the previous date is less than the current minus 1
if ($i-1 > $prev) {
// build the new range
$str .= '-'.$prev.','.$i;
}
}
$prev = $i;
}
}
// build the last range
if ($i-1 > $prev) {
$str .= '-'.$prev;
}
echo "str=$str\n";
NB: it must run under php 5.1.6 (i can't upgrade).
FYI : the numbers represent days of month so they are limited to 1-31.
Edit:
From a given range of dates (1-3,6,7-8), i'd like obtain another list (1-3,6-8) where all the ranges are recalculated and ordered.
Perhaps not the most efficient, but shouldn't be too bad with the limited range of values you're working with:
$in = '1-3,5,6-4,31,9,19,10,25-20';
$inSets = explode(',',$in);
$outSets = array();
foreach($inSets as $inSet) {
list($start,$end) = explode('-',$inSet.'-'.$inSet);
$outSets = array_merge($outSets,range($start,$end));
}
$outSets = array_unique($outSets);
sort($outSets);
$newSets = array();
$start = $outSets[0];
$end = -1;
foreach($outSets as $outSet) {
if ($outSet == $end+1) {
$end = $outSet;
} else {
if ($start == $end) {
$newSets[] = $start;
} elseif($end > 0) {
$newSets[] = $start.'-'.$end;
}
$start = $end = $outSet;
}
}
if ($start == $end) {
$newSets[] = $start;
} else {
$newSets[] = $start.'-'.$end;
}
var_dump($newSets);
echo '<br />';
You just have to search your data to get what you want. Split the input on the delimiter, in your case ','. Then sort it somehow, this safes you searching left from the current position. Take you first element, check whether it's a range and use the highest number in this range (3 out of 1-3 range or 3 if 3 is a single element) for further comparisions. Then take the 2nd element in your list and check if it's a direct successor of the last element. If yes combine the 1st and 2nd elements/range to a new range. Repeat.
Edit: I'm not sure about PHP but a regular expression is a bit overkill for this problem. Just look for a '-' in your exploded array, then you know it's a range. Sorting the exp. array safes you the backtracking, the stuff you are doing with $prev. You could also explode every element in the exploded array on '-' and check if the resulting array has a size > 1 to learn whether an element is a range or not.
Looking at the problem from an algorithmic stand-point, let's consider the limitations that you've put on the problem. All numbers will be from 1-31. The list is a collection of "ranges", each of which is defined by two numbers (start and end). There is no rule for whether start will be more, less than, or equal to end.
Since we have an arbitrarily large list of ranges but a definite means of sorting/organizing these, a divide and conquer strategy may yield the best complexity.
At first I typed out a very long and careful explanation of how I created each step in this algorithm (the dividing portion, the conquering potion, optimizations, etc.) however the explanation got extremely long. To shorten it, here's the final answer:
<?php
$ranges = "1-3,5,6-4,31,9,19,10,25-20";
$range_array = explode(',', $ranges);
$include = array();
foreach($range_array as $range){
list($start, $end) = explode('-', $range.'-'.$range); //"1-3-1-3" or "5-5"
$include = array_merge($include, range($start, $end));
}
$include = array_unique($include);
sort($include);
$new_ranges = array();
$start = $include[0];
$count = $start;
// And begin the simple conquer algorithm
for( $i = 1; $i < count($include); $i++ ){
if( $include[$i] != ($count++) ){
if($start == $count-1){
$new_ranges[] = $start;
} else {
$new_ranges[] = $start."-".$count-1;
}
$start = $include[$i];
$count = $start;
}
}
$new_ranges = implode(',', $new_ranges);
?>
This should (theoretically) work on arrays of arbitrary length for any positive integers. Negative integers would get tripped up since - is our delimiter for the range.

Categories