PHP Array Zeros except for one, extract that value - php
I have an array with values that change from time to time. It will usually look like this:
Array ( [0] => 0 [1] => 0 [2] => 9876 [3] => 0 [4] => 0 [5] => 0 [6] => 0 [7] => 0 [8] => 0 [9] => 0 [10] => 0 [11] => 0 )
All of the Values will be 0 except for one (index location will change).
If more than one value is greater than 0, I need to execute a specific command.
Else, if only one value is greater than 0, I need to take that value and pass it to a specific command.
Create a new array containing only the non-null values. array_filter without callback will return all elements which do not evaluate to FALSE.:
$a = array(...);
$values = array_filter($a);
switch(count($values)) {
case 0: echo 'All 0!'; break;
case 1: specificCommandWithValue($values[0]); break;
default: executeSpecificCommand(); break;
}
If you have false-y values, you want to keep (FALSE, NULL, '0', ''), pass a callback which does strict value comparison: function($el) { return $el !== 0; }
try
$count =0;
foreach($array as $item){
if($item !=0){
$count = $count+1;
}
}
if($count > 1){
//execute a specific command
}elseif($count == 1){
// take that value and pass it to a specific command
}else{
//all value are zero
}
Try this code.
<?PHP
$array = array(
"1" => "0",
"2" => "0",
"3" => "0",
"4" => "24",
"5" => "0");
$zero_plus_keys = 0;
$zero_plus_val = array();
foreach($array as $key => $val)
{
if($val > 0)
{
$zero_plus_keys++;
$zero_plus_val = array($key,$val);
}
}
if($zero_plus_keys == 1)
{
echo "In array '".$zero_plus_val[0]."' key contains Greater than zero value. the value is = '".$zero_plus_val[1]."'";
}
elseif($zero_plus_keys > 1)
{
echo "More keys Greater than zero(0)";
}
else
{
echo "All keys contains zero(0)s only...";
}
?>
This is #NullPointer's answer, but I added in a variable to hold "that value".
$count =0;
$nonzero = null;
foreach($array as $item){
if($item !=0){
$count = $count+1;
$nonzero = $item;
}
}
if($count > 1){
//execute a specific command
}elseif($count == 1){
specific_command($nonzero);
}else{
//all value are zero
}
$array = 'your array';
function Find($array){
$count = 0;
$needle = -1;
foreach($array as $item){
if($item > 0){
$count++;
$needle = $item;
}
if($count > 1)
return -1; //error as number of non-zeroes greater than 1
}
if($count > 0)
return $needle; //returns the required single non-zero item
return 0; // returns zero if nothing is found
}
$return = Find($array);
Just for fun :P
$array = array_flip(array_flip($array));
sort($array);
if (count($array) > 2) moreThanOne();
else onlyOne($array[1]);
Filter the array and if there is only one use current() to get it:
if(count($n = array_filter($array)) == 1) {
execute_command(current($n));
} else {
execute_command();
}
Related
Get nearest sequence result from an array and given pattern with PHP
I am trying to get year and month from the letters using established sequence. I know that the sequence is based on the following letters: $letters = array('B','C','D','F','G','H','J','K','L','M','N','P','R','S','T','V','W','X','Y','Z'); It started with 0000BBB and when it reaches 9999 it becomes BBC, BBD etc. So I don't need the numbers in that case and only letters as I have a list of last registered sequence per year and month like this: $plates = array( array('2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'), array('2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'), array('2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'), array('2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'), array('2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'), array('2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'), array('2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'), array('2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'), array('2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'), array('2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'), array('2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'), array('2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'), array('2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'), array('2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'), array('2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'), array('2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'), array('2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'), array('2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'), array('2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR') ); That means that array index 0 is the year and from 1 to 12 would be month. I am trying to find a match but then realize I can not search exact value and need to look for nearest value based on letters. I would deeply appreciate if anyone could direct me in right direction what would be the best method of doing this. This is a test so far but this will just return an exact match, I would have to search any possible letters such as KHW as an example that would have to match as nearest value to KHX foreach ($plates as $key => $val) { $search = array_search('KHX', $plates[$key]); if($search){ echo $search."\n"; echo $plates[$key][0]; break; } }
You can solve it with O(log n) with a binary search. But in a more straightforward solution, you can solve it with O(n). You can calculate the difference between each word with the below algorithm. <?php function strToInt($str) { $result = 0; for ($i = 0; $i < strlen($str); $i++) { $result = $result * 100 + ord($str[$i]); } return $result; } function find($searchStr) { $plates = [ ['2018','KHF','KHX','KJV','KKN','KLM','KML','KNK','KPD','KPR','KPT','----','----'], ['2017','JWN','JXF','JYB','JYT','JZP','KBM','KCH','KCV','KDK','KFB','KFV','KGN'], ['2016','JLN','JMF','JMY','JNR','JPK','JRG','JRZ','JSL','JTB','JTR','JVH','JVZ'], ['2015','JCK','JCY','JDR','JFG','JFW','JGP','JHJ','JHT','JJH','JJW','JKK','JKZ'], ['2014','HVN','HVZ','HWM','HXB','HXN','HYD','HTY','HZB','HZL','HZZ','JBL','JBY'], ['2013','HNT','HPC','HPN','HPY','HRK','HRX','HSK','HSR','HSZ','HTK','HTV','HVF'], ['2012','HJC','HJM','HKB','HKL','HKX','HLK','HLW','HMD','HML','HMT','HNC','HNK'], ['2011','HBP','HCB','HCR','HDC','HDR','HFF','HFT','HGC','HGM','HGX','HHH','HHT'], ['2010','GTC','GTS','GVM','GWC','GWV','GXP','GYD','GYM','GYX','GZJ','GZT','HBG'], ['2009','GKS','GLC','GLP','GMC','GMN','GNF','GNY','GPJ','GPW','GRM','GSC','GSR'], ['2008','FZR','GBN','GCK','GDH','GFC','GFY','GGV','GHG','GHT','GJJ','GJV','GKH'], ['2007','FKY','FLV','FNB','FNZ','FRC','FSJ','FTP','FVJ','FWC','FXB','FXY','FYY'], ['2006','DVW','DWT','DXZ','DYY','FBC','FCJ','FDP','FFK','FGF','FHD','FJD','FKC'], ['2005','DFZ','DGX','DHZ','DKB','DLD','DMJ','DNP','DPK','DRG','DSC','DTB','DVB'], ['2004','CRV','CSS','CTT','CVR','CWR','CXT','CYY','CZP','DBJ','DCH','DDG','DFF'], ['2003','CDV','CFM','CGJ','CHF','CJC','CKB','CLD','CLV','CMM','CNK','CPF','CRC'], ['2002','BSL','BTF','BTZ','BVW','BWT','BXP','BYP','BZF','BZV','CBP','CCH','CDC'], ['2001','BFJ','BGF','BHG','BJC','BKB','BLC','BMF','BMW','BNL','BPG','BRB','BRT'], ['2000','---','---','---','---','---','---','---','---','BBJ','BCD','BCY','BDR'] ]; $minYear = null; $minKey = null; $minDiff = strToInt('ZZZ'); $searchInt = strToInt($searchStr); for ($i = 0; $i < count($plates); $i++) { for ($j = 1; $j < 13; $j++) { if(abs($searchInt - strToInt($plates[$i][$j])) < $minDiff) { $minDiff = abs($searchInt - strToInt($plates[$i][$j])); $minYear = $plates[$i][0]; $minKey = $plates[$i][$j]; } } } return [$minYear, $minKey]; } print_r(find('KHW'));
The code down below is by no means optimized, but it's rather a concept of how you might solve your problem. //Flatten out array (one dimension without years and ----) $flatten = array(); foreach($plates as $platevalues) { foreach($platevalues as $pv) { if ($pv != '---' && $pv != '----' && intval($pv) == 0) { //Create a string only if valid letters included in the $letters-array //This string is then added to the new array that is flattened out $pv2 = ''; for($i=0;$i<strlen($pv);$i++) { $letter = substr($pv,$i,1); if (in_array($letter, $letters) !== false) { $pv2 .= $letter; } } $flatten[] = $pv2; } } } //Do the search $search = 'GWN'; $search_result = ''; //Create a new search string based on first found in flattened //plates array (first G, then GW, then GWN) for($i=0;$i<strlen($search);$i++) { foreach($flatten as $key=>$f) { if (substr($search,0,$i+1) == substr($f,0,$i+1)) { $search_result .= substr($search,$i,1); break; } } } /* $search_result is: GW */ //Create a new array where all items that begins with GW are included $result = []; foreach($flatten as $key=>$item) { if (substr($search_result,0,strlen($search_result)) == substr($item,0,strlen($search_result))) { $result[] = $item; } } /* $result = array (size=2) 0 => string 'GWC' (length=3) 1 => string 'GWV' (length=3) */ //Create an array with total ASCII-value for each item //in the $result array above $result_o = []; foreach($result as $item) { $o = 0; for($i=0;$i<strlen($item);$i++) { $o += ord(substr($item,$i,1)); } $result_o[]= $o; } /* $result_o = array (size=2) 0 => int 225 1 => int 244 */ //Get the total ASCII-value for the original search string $search_o = 0; for($i=0;$i<strlen($search);$i++) { $search_o += ord(substr($search,$i,1)); } /* $search_ o = 236 */ //Find closest value in the $result_o (ASCII) - array compared (225,244) //to the original $search_o ASCII value above (236) $closest = 0; $use_key = 0; foreach($result_o as $key=>$item) { if ($closest == 0 || abs($search_o - $closest) > abs($item - $search_o)) { $closest = $item; $use_key = $key; } } /* $closest = 244 (it's closer to 236 than 225 is) $use_key = 1 */ To get the result you have: /* $result = array (size=2) 0 => string 'GWC' (length=3) 1 => string 'GWV' (length=3) */ //This should print out GWV echo 'result=' . $result[$use_key];
PHP Incrementing Array by 1
I have a simple array $iteration=[0,1,2,3,4] and I am trying to build a function to increment it to a max value of $max=12 for example and I can't reuse the same number for 2 keys. But so far I have very little success. Here is what I have now. //$iteration is my array and $max is the maximum value a key can have. IncrementIteration($iteration,$max){ $count=count($iteration); while($count > 0){ if( ($iteration[($count-1)] < $max) ){ $iteration[($count-1)]++; break; } $count--; } return $iteration; } But this never resets the keys that follows the incremented key and does not take into account if the number has already been used. Here is what I am looking for as example of results: print_r(IncrementIteration([0,1,2],12)) Output : Array ( [0] => 0 [1] => 1 [2] => 3 ) print_r(IncrementIteration([0,1,12],12)) Output : Array ( [0] => 1 [1] => 2 [2] => 3 ) print_r(IncrementIteration([0,11,12],12)) Output : Array ( [0] => 1 [1] => 2 [2] => 3 ) This would be the highest possible incrementation. print_r(IncrementIteration([10,11,12],12)) Output : Array ( [0] => 10 [1] => 11 [2] => 12 ) Thanks for any help on this code. I am adding the other functions to add more clarity about the purpose of this function. function ReverseSUM($value,$array){ global $debug; $count=count($array); $count=3; $values=array(); while($count > 0){ //Init of While Iteration $iteration=GenerateIteration($count); //We iterate while(SumIteration($iteration,$array) != $value){ if($iteration === IncrementIteration($iteration,(count($array)-1))){ break; } else { $iteration=IncrementIteration($iteration,(count($array)-1)); } //End of While Iteration } //End of While Iteration if(SumIteration($iteration,$array) == $value){ array_push($values,$iteration); } unset($iteration); if($debug){echo "</div>";}; $count--; } return $values; } function GenerateIteration($number){ $iteration=array(); $count = 0; while($count < $number){ array_push($iteration,$count); $count++; } return $iteration; } function IncrementIteration($iteration,$max){ $count=count($iteration); while($count > 0){ if( ($iteration[($count-1)] < $max) ){ $iteration[($count-1)]++; break; } $count--; } return $iteration; } function SumIteration($iteration,$array){ $result=array(); foreach($iteration as $key){ array_push($result,$array[$key]); } return array_sum($result); }
May be some thing like this can help, function unique_keys_array($array) { $temp_array = array(); $i = 0; $key_array = array(); foreach($array as $key) { if (!in_array($key, $key_array)) { $key_array[$i] = $key; $temp_array[$i] = $key; } $i++; } return $temp_array; } print_r(unique_keys_array([1,2,2,3,4,5,6,7,8,8,9,9])); returns Array ( [0] => 1 [1] => 2 [3] => 3 [4] => 4 [5] => 5 [6] => 6 [7] => 7 [8] => 8 [10] => 9 )
Here is my final code for my Reverse Sum function ReverseSUM($value,$array){ ini_set('max_execution_time', 10); if (!function_exists('GenerateIteration')) { function GenerateIteration($number){ global $debug; $iteration=array(); $count = 0; while($count < $number){ $count++; array_push($iteration,$count); } return $iteration; } } if (!function_exists('IncrementIteration')) { function IncrementIteration($iteration,$max){ global $debug; $count=count($iteration); while($count > 0){ if( $iteration[($count-1)] < $max ){ $iteration[($count-1)]++; if($count != count($iteration)){ $count2=$count; while($count2 <= count($iteration)){ if($count2 != count($iteration)){ // if( ($iteration[$count2] < $max) ){ $iteration[$count2]=($iteration[($count2-1)]+1); // } } $count2++; } } break; } $max--; $count--; } return $iteration; } } if (!function_exists('SumIteration')) { function SumIteration($iteration,$array){ global $debug; $result=array(); foreach($iteration as $key){ array_push($result,$array[$key]); } return array_sum($result); } } $count=count($array); $count=3; $values=array(); while($count > 0){ //Init of While Iteration $iteration=GenerateIteration($count); //We iterate while(SumIteration($iteration,$array) != $value){ if($iteration === IncrementIteration($iteration,(count($array)-1))){ break; } else { $iteration=IncrementIteration($iteration,(count($array)-1)); } //End of While Iteration } //End of While Iteration if(SumIteration($iteration,$array) == $value){ array_push($values,$iteration); } unset($iteration); $count--; } return $values; } And here is how I display the results: <?php foreach($recap as $line => $value){ ?> <?php if($line<2){?> <table border="1"> <tr> <th colspan="2" style="text-align:left;">Line <?=$line?> - <?=$value?></th> </tr> <tr> <th>Iteration</th> <th>Values</th> </tr> <?php foreach(ReverseSUM($value,$invoice) as $iteration => $values){?> <tr> <td><?=$iteration?></td> <td> <?php foreach($values as $array){?> <?=($array +1)?><br /> <?php } ?> </td> </tr> <?php } ?> </table> <?php } ?> <?php } ?> The $recap array simply contains the total values we are searching for. And the $invoice array contains all the invoice lines totals. Code available on GitHub : https://github.com/LouisOuellet/ReverseSUM Sheers
How get a (fixed) value based on number range
I have a number, e.g. $humidity I need to check value of this number and get a fixed value if number is in a predetermined range. E.g. if ($humidity<30) { return 'dry'; } if ($humidity>=30 && $humidity <=40) { return 'wet' } if ($humidty>40 && $humidity<70) { return 'confortable' } And so on. Is there another possibility to don't use 4/5 different if ?
As long as you process the values in order, you don't need both the upper and lower values of each range. Then you can utilize short-circuiting and just put everything in a loop: function nameOf($humidity) { $list = [ 30 => 'dry', 40 => 'wet', 70 => 'comfortable', ]; foreach ($list as $value => $name) { if ($humidity < $value) { return $name; } } return 'default'; }
I think switch is great for this usage: $result = null; switch(true) { case $humidity < 30: $result = 'dry'; break; case $humidity >= 30 && $humidity < 40: $result = 'wet'; break; case $humidty > 40 && $humidity < 70: $result = 'comfortable'; break; } return $result;
you can create an range array for your temps and then array_walk that to find the right range. $h=40; $harr = [ 0 => 'dry', 1 => 'wet', 2 => 'confy']; $range = array_flip(range(0, 100, 30)); array_walk($range, 'findHumidity', $range); var_dump($harr[$result]); function findHumidity($value, $key, $r){ global $h; //if you using a class and properties you can ignore these two lines global $result; $normalRange = array_flip($r); if($h> $key && $normalRange[$value+1]!=null && $h<= $normalRange[$value+1]){ $result = $value; } } Working example: https://3v4l.org/fWLDu (a simplified version: https://3v4l.org/ROjWk) or you can define the range array manually like here: https://3v4l.org/B0oTU
Convert my script in recursive way?
I have script who searches closest searched number. So for example, let say that in array are this numbers: '0' => 1.72 '0.25' => 1.92 '0.75'=> 2.35 '1' => 3.00 I am searching for 0.50 handicap, so 0.25 and 0.75 are in same range from 0.50. In this situations i want to get greater number, what is 0.75 in this example. Code what works is this: function getClosest($search, $arr) { $closest = null; $num_arr = array(); $odd = 0.00; $i = 0; foreach ($arr as $handicap=>$item) { //first closest number if ($closest === null || abs($search - $closest) > abs($handicap - $search)) { $closest = $handicap; $odd = $item; } else{ $num_arr[$handicap] = $item; } } $newclosest = null; $newodd = 0.00; foreach($num_arr as $handicap=>$newitem){ //second closest number if ($newclosest === null || abs($search - $closest) > abs($handicap - $search)) { $newclosest = $handicap; $newodd = $newitem; } } //if difference between first and second number are same if(abs($search - $closest) == abs($newclosest - $search)){ if($newclosest > $closest){ //if second number is greater than first $closest = $newclosest; $odd = $newodd; } } return array('handicap'=>$closest,'odd'=>$odd); } I see that i can use recursion here, but i am not experienced in using recursion. I know that i need call it inside like this: $rec_arr = getClosest($num_arr,$search); but i get blank page even i dump function output.
use array_map function, $data = array('0'=>1.72,'0.75'=> 2.35,'0.25'=>1.92,'1' => 3.00); $v = 0.5; // search value $x = null; // difference value $y = array(); // temporary array array_map(function($i)use($data,$v,&$x,&$y){ if(isset($x)){ if($x > abs($i-$v)){ // if difference value is bigger than current $x = abs($i-$v); $y = array($i=>$data[$i]); }else if($x == abs($i-$v)){ // if difference value is same $key = array_keys($y); $y = $key[0] < $i ? array($i=>$data[$i]) : $y; } }else{ // first loop $x = abs($i-$v); $y = array($i=>$data[$i]); } },array_keys($data)); print_r($y); // result output Array ( [0.75] => 2.35 ), hope this help you.
//$a is array to be searched //$s is search key //$prev_key and $next_key will be output required $a = array('0'=>1,'0.25'=>123,'0.75'=>456,'0.78'=>456,'1'=>788); $s = '0'; if(isset($a[$s])){ echo $s; } else{ reset($a);//good to do while(key($a) < $s){ next($a); } $next_key = key($a); prev($a); $prev_key = key($a); echo $prev_key.'-'.$next_key; } The above code uses array internal pointers. I think this may help you.. source: https://stackoverflow.com/a/4792770/3202287
PHP getting count for values that falls within expected ranges
I have a list containing a bunch of values from 1-400. I am trying to divide the data into ranges like [1-50], [51-100], .. , [351-400] and get the count for the values that falls within the range given . I basically have the code working. So, my question would be is there a better way to do this or what would be a good practise for this? $temp = array(); //temp array to store the values from mysql $final_array = array //final array to store the counts from the range initialized to 0 ( "0" => 0, "1-50" => 0, "51-100" => 0, "101-150" => 0, "151-200" => 0, "201-250" => 0, "251-300" => 0, "301-350" => 0, "351-400" => 0 ); $sql = "SELECT count(*) AS total FROM user GROUP BY user_id"; $statement = $DB_->link->prepare ( $sql ); $statement->execute (); if ($result = $statement->get_result ()) { while ( $row = $result ->fetch_assoc() ) { $temp [] = $row; } } else { die(mysql_error()); } foreach ($temp as $child) { if( $child['total'] >= 351 && $child['total'] <= 400) { $final['351-400']++; } elseif( $child['total'] >= 301 && $child['total'] <= 350) { $final['301-350']++; } ... elseif( $child['total'] >= 1 && $child['total'] <= 50) { $final['1-50']++; } } Desired results Array ( [0] => 0 [1-50] => 1 [51-100] => 0 [101-150] => 0 [151-200] => 1 [201-250] => 0 [251-300] => 4 [301-350] => 5 [351-400] => 18 )
I would iterate over the keys of final_array, exploding them using - as the delimiter. While this method is slower than what you have, as it's iterating over final_array for each row returned from the database, it is much more maintainable, as it seamlessly handles keys for exact matches (only 1 number), and arbitrary ranges. Adding more buckets simply requires editing the final_array array, rather than changing a bunch of lines of code. foreach ($temp as $child) { foreach($final_array as $key => $value) { if (strpos($key, '-') === false) { if ($child['total'] == intval($key)) { $final_array[$key]++; } } else { list($min, $max) = explode('-', $key); if ($child['total'] >= intval($min) && $child['total'] <= intval($max)) { $final_array[$key]++; } } } } I would also forgo the use of the $temp array, simply processing the results as they are returned: if ($result = $statement->get_result ()) { while ( $child = $result->fetch_assoc() ) { foreach($final_array as $key => $value) { if (strpos($key, '-') === false) { if ($child['total'] == intval($key)) { $final_array[$key]++; } } else { list($min, $max) = explode('-', $key); if ($child['total'] >= intval($min) && $child['total'] <= intval($max)) { $final_array[$key]++; } } } } } else { die(mysql_error()); } The most efficient system would load all the results in an array, pass that array through array_count_values, and then aggregate those.
This is the best way which you used & for single key count we use PHP function array_count_values