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

Categories