I would like to find the second highest variable in an array.
For example if I have:
$cookies = array(
"chocolate" => "20",
"vanilla" => "14",
"strawberry" => "18",
"raspberry" => "19",
"bluebery" => "29"
);
I can use max($cookies) to find the highest variable, which is "bluebery" => "29".
But how do I find the second highest? "chocolate" => "20"
Sort it and get the second item is the easiest way:
arsort($cookies);
$keys = array_keys($cookies);
echo $keys[1]; // chocolate
echo $cookies[$keys[1]]; // 20
If you want a more efficient way, you can also do it manually, by keeping track of both the highest and second-highest items at the same time:
function secondMax($arr) {
$max = $second = 0;
$maxKey = $secondKey = null;
foreach($arr as $key => $value) {
if($value > $max) {
$second = $max;
$secondKey = $maxKey;
$max = $value;
$maxKey = $key;
} elseif($value > $second) {
$second = $value;
$secondKey = $key;
}
}
return array($secondKey, $second);
}
Usage:
$second = secondMax($cookies);
echo "{$second[0]} => {$second[1]}"; // chocolate => 20
For fun you could use max() twice :)
For example:
Duplicate the array
Run max()
Remove the max
Run max() again
The alternative would to sort the array based on values and get the second element of the array. I'd be curious which is faster. Likely the sort.
arsort($cookies) AND array_shift($cookies) AND list($k, $v) = each($cookies);
echo "$k => $v"; // chocolate => 20
rsort($cookies);
echo $cookies[1];
Try :
asort($cookies);
end($cookies);
prev($cookies);
list($key,$value) = each($cookies);
or reverse it
arsort($cookies);
reset($cookies);
next($cookies);
list($key,$value) = each($cookies);
** Edit **
I thought I'd share this anyway, if someone would stumble across this and need it :
/**
* Returns the key => value pair with the specific rank.
* if $rank is 0, falase is returned. If $rank is positive,
* then the $rank th smallest pair is returned. If $rank
* is negative, then the $rank th biggest pair is returned.
* If $rank range is outside the size of the array, false
* is returned. If a callable function is provided, it will
* be used to sort the data. If $keySort is true, then the
* data will be sorted by keys instead (the callback functions
* will receive the keys to compare instead of values)
*
* #param $data array
* #param $rank int
* #param $cmd_function callable (optional)
* #param $keySort boolean (optional)
* #return array the key => value pair or false
*/
function findByRank($data, $rank, $cmd_function = null, $keySort = false) {
if (($rank == 0) || (abs($rank) > count($data))) {
return false;
}
$sort = ($keySort?'k':'a').'sort';
if ($cmd_function != null) {
$sort = 'u'.$sort;
$sort($data, $cmd_function);
} else {
$sort($data);
}
if ($rank > 0) {
reset($data);
$next = 'next';
} else {
end($data);
$next = 'prev';
$rank = abs($rank);
}
while (--$rank > 0) $next($data);
return each($data);
}
$cookies = array(
"chocolate" => "20",
"vanilla" => "14",
"strawberry" => "18",
"raspberry" => "19",
"bluebery" => "29"
);
header('Content-type:text/plain; charset=utf-8');
var_dump(findByRank($cookies, -10)); // -> false
var_dump(findByRank($cookies, -2)); // -> 'chocolate' key=>value pair
var_dump(findByRank($cookies, -1)); // -> 'blueberry' key=>value pair
var_dump(findByRank($cookies, 0)); // -> false
var_dump(findByRank($cookies, 1)); // -> 'vanilla' key=>value pair
var_dump(findByRank($cookies, 3)); // -> 'raspberry' key=>value pair
Sort the array descending and take the second value. Or, to be save, take the first value and go through the array until you find a smaller one.
function second_largest($arr)
{
sort($arr, SORT_NUMERIC);
return($arr[count($arr) - 2]);
}
//echo 3
echo second_largest(array(0, 3, 4, 1, 2));
Check this URL
http://maheshbokkisam.blogspot.in/2013/04/find-nth-highest-value-in-array-without.html
Find Nth/ N th highest value from given array without using any sorting in PHP
$ar = array(23,56,87,12,98,85,24,54,99,100,1,4,5,2,76,37,92);
$n = count($ar) - 5;
for($i = 0; $i < $n; $i++){
// Get the max value from array // get the Nth value from last loop
echo $a = max($ar);
echo "<br /><pre>"; print_r($ar);
$ar = array_flip($ar); // Flip the array
//print_r($ar);
unset($ar[$a]); // Unset the max value from array
//print_r($ar);
$ar = array_flip($ar); // Flip the array
echo "</pre>";
echo "<hr />";
}
<?php
// Finding Second highest number (In case of index of array is random)
$arr = [-5 => 33, -4 => -2, 8 => 0, 44, 44, 44, 44, 44];
$max = -INF;
$secondMax = -INF;
$size = sizeof($arr);
if ($size > 1) {
foreach ($arr as $key => $value) {
echo "KEY-> ", $key, "VALUE->", $value, "\n";
if ($value > $max) {
$max = $value;
} else {
if ($value < $max && $value > $secondMax) {
$secondMax = $value;
}
}
}
} else if ($size == 0) {
$max = "No Max element";
$secondMax = "No Second highest element";
} else {
foreach ($arr as $key => $value) {
$max = $arr[$key];
$secondMax = "No second highest element";
}
}
echo "maxvalue = ", $max, "\n";
echo "secondmax =", $secondMax;
Related
In my code I have two elements which has the same age "Joe"=>"43" and "Rob"=>"43" .
My code output is:
Joe
I want to output:
Joe and Rob
Because they has the highest value.
This is my code:
<?php
$cur = 1;
$age = array("Peter" => "35", "Ben" => "37", "Joe" => "43", "Rob" => "43");
$new_array = array();
arsort($age);
$new_array = $age;
$key = array_search(max($new_array), $new_array);
while ($cur > 0) {
echo $key;
$cur--;
}
?>
I'd change the keys and values in the array, then sort by key and return the values of the first key:
$ages = array("Peter" => "35", "Ben" => "37", "Joe" => "43", "Rob" => "43");
$new = array();
foreach ($ages as $name => $age) {
$new[$age][] = $name;
}
uksort($new, function($ka, $kb) { return $kb - $ka; }); // or just krsort($new);
$new = array_values($new)[0]; // <- to use this you have to have at least PHP 5.4
// if you have PHP < 5.4 you can simply do it in two steps:
// $new = array_values($new);
// $new = $new[0];
See it in action!
EDIT: even simpler!
$ages = array("Peter" => "35", "Ben" => "37", "Joe" => "43", "Rob" => "43");
$max = max($ages);
$new = array_keys(array_filter($ages, function ($age) use ($max) { return $age == $max; }));
Use:
$people = array("Peter" => "35", "Ben" => "37", "Joe" => "43", "Rob" => "43");
$max = max($people);
$result = array_filter($people, function($age) use ($max){ return $max == $age; });
The result is:
Array
(
[Joe] => 43
[Rob] => 43
)
Just check it manually:
$age = array("Peter" => "35", "Ben" => "37", "Joe" => "43", "Rob" => "43");
$new_array = array();
arsort($age);
$new_array = $age;
$max = max($new_array);
$results = array();
foreach ($new_array as $key => $val) {
if ($val == $max) {
$results[] = $key;
}
}
echo implode(' and ', $results);
// will output "joe and bob"
I like the answer of #matteo-tassinari and #evilive much more and wanted to propose it myself. But since the question of efficency came up, here is a solution using only one loop and therefore has a linear time complexity:
<?php
$max = ~PHP_INT_MAX;
$result = [];
foreach($age as $key => $value) {
if($value > $max) {
$result = [ $key => $value ];
$max = $value;
}
if($value == $max) {
$result[$key] = $value;
}
}
var_dump($result);
And there exists another solution, that uses bucket sort:
function bucket($ages) {
$buckets = [];
foreach($ages as $key => $value) {
$buckets[$value][] = $key;
}
return $buckets[max(array_keys($buckets))];
}
Regarding the discusson about peformance and scalability, I wrote a small benchmark script for four kinds of proposed solutions (loop, sort, filter, bucket):
<?php
function loop($ages) {
$max = 0;
$result = [];
foreach($ages as $key => $value) {
if($value > $max) {
$result = [ $key => $value ];
$max = $value;
}
if($value == $max) {
$result[$key] = $value;
}
}
return array_keys($result);
}
function filter($ages) {
$max = max($ages);
$new = array_filter($ages, function ($age) use ($max) { return $age == $max; });
return array_keys($new);
}
function bucket($ages) {
$buckets = [];
foreach($ages as $key => $value) {
$buckets[$value][] = $key;
}
return $buckets[max(array_keys($buckets))];
}
for($n = 2; $n < 10000000; $n*=2) {
$ages = [];
for($i = 0; $i < $n; $i++) {
$ages['name_'.$i] = rand(0,100);
}
$start = microtime(true);
echo $n.';';
loop($ages);
echo (microtime(true) - $start).';';
$start = microtime(true);
arsort($ages);
echo (microtime(true) - $start).';';
$start = microtime(true);
filter($ages);
echo (microtime(true) - $start).';';
bucket($ages);
echo (microtime(true) - $start).';';
echo PHP_EOL;
}
Limited Live Test
Please double-check if this is right: Using php-5.6.15 on the command line, my timings look something like this:
elements;loop;sort;filter;bucket
...
4096;0.001507;0.009868;0.01211;0.01453;
8192;0.003704;0.002483;0.02488;0.03035;
16384;0.006660;0.01010;0.05396;0.06723;
32768;0.01417;0.01271;0.09163;0.1163;
...
1048576;0.4227;0.9791;2.983;3.943;
2097152;0.8572;2.320;6.064;8.020;
4194304;1.787;4.981;11.90;16.04;
8388608;3.892;10.84;24.76;33.31;
For small number of elements, the difference between the methods is not really big, but as you can see, for the largest value the loop method is two times faster than sort, 8 times faster than filter and eleven times faster than bucket. So if your array is huge, you should use loop.
I'd do something like this
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43","Rob"=>"43");
$max = max($age); //get the highest age
foreach ($age as $key => $value) { //iterate through $age array
if ($value == $max) { //if the value is equal to max age
echo $key."<br />"; // then echo the key
}
}
You can use the array methods next and key.
With next() you will move the array pointer one position. With key() you will get the key of the element of the array pointer. So the final code will be something like this:
$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43","Rob"=>"43");
arsort($age);
echo key($age);
next($age);
echo key($age);
Check it working here.
I'm wondering why no one is using built in solution:
$age = array("Peter"=>"35","Ben"=>"37","Joe"=>"43","Rob"=>"43");
$new = array_keys($age, max($age));
returns
array('Joe', 'Rob')
https://www.php.net/manual/en/function.array-keys.php says:
array_keys ( array $array , mixed $search_value [, bool $strict = FALSE ] ) : array
If a search_value is specified, then only the keys for that value are returned. Otherwise, all the keys from the array are returned.
This question already has answers here:
Populate array of integers from a comma-separated string of numbers and hyphenated number ranges
(8 answers)
Closed 6 months ago.
I'm trying to normalize/expand/hydrate/translate a string of numbers as well as hyphen-separated numbers (as range expressions) so that it becomes an array of integer values.
Sample input:
$array = ["1","2","5-10","15-20"];
should become :
$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];
The algorithm I'm working on is:
//get the array values with a range in it :
$rangeArray = preg_grep('[-]',$array);
This will contain ["5-10", "16-20"]; Then :
foreach($rangeArray as $index=>$value){
$rangeVal = explode('-',$value);
$convertedArray = range($rangeVal[0],$rangeVal[1]);
}
The converted array will now contain ["5","6","7","8","9","10"];
The problem I now face is that, how do I pop out the value "5-10" in the original array, and insert the values in the $convertedArray, so that I will have the value:
$array = ["1","2",**"5","6","7","8","9","10"**,"16-20"];
How do I insert one or more values in place of the range string? Or is there a cleaner way to convert an array of both numbers and range values to array of properly sequenced numbers?
Here you go.
I tried to minimize the code as much as i can.
Consider the initial array below,
$array = ["1","2","5-10","15-20"];
If you want to create a new array out of it instead $array, change below the first occurance of $array to any name you want,
$array = call_user_func_array('array_merge', array_map(function($value) {
if(1 == count($explode = explode('-', $value, 2))) {
return [(int)$value];
}
return range((int)$explode[0], (int)$explode[1]);
}, $array));
Now, the $array becomes,
$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];
Notes:
Casts every transformed member to integer
If 15-20-25 is provided, takes 15-20 into consideration and ignores the rest
If 15a-20b is provided, treated as 15-20, this is result of casing to integer after exploded with -, 15a becomes 15
Casts the array keys to numeric ascending order starting from 0
New array is only sorted if given array is in ascending order of single members and range members combined
Try this:
<?php
$array = ["1","2","5-10","15-20"];
$newdata = array();
foreach($array as $data){
if(strpos($data,'-')){
$range = explode('-', $data);
for($i=$range[0];$i<=$range[1];$i++){
array_push($newdata, $i);
}
}
else{
array_push($newdata, (int)$data);
}
}
echo "<pre>";
print_r($array);
echo "</pre>";
echo "<pre>";
print_r($newdata);
echo "</pre>";
Result:
Array
(
[0] => 1
[1] => 2
[2] => 5-10
[3] => 15-20
)
Array
(
[0] => 1
[1] => 2
[2] => 5
[3] => 6
[4] => 7
[5] => 8
[6] => 9
[7] => 10
[8] => 15
[9] => 16
[10] => 17
[11] => 18
[12] => 19
[13] => 20
)
Problem solved!
Using range and array_merge to handle the non-numeric values:
$array = ["1","2","5-10","15-20"];
$newArray = [];
array_walk(
$array,
function($value) use (&$newArray) {
if (is_numeric($value)) {
$newArray[] = intval($value);
} else {
$newArray = array_merge(
$newArray,
call_user_func_array('range', explode('-', $value))
);
}
}
);
var_dump($newArray);
It's easier to find out the minimum and maximum value and create the array with them. Here's an example:
$in = ["1","2","5-10","15-20"];
$out = normalizeArray($in);
var_dump($out);
function normalizeArray($in)
{
if(is_array($in) && sizeof($in) != 0)
{
$min = null;
$max = null;
foreach($in as $k => $elem)
{
$vals = explode('-', $elem);
foreach($vals as $i => $val)
{
$val = intval($val);
if($min == null || $val < $min)
{
$min = $val;
}
if($max == null || $val > $max)
{
$max = $val;
}
}
}
$out = array();
for($i = $min; $i <= $max; $i++)
{
$out[] = $i;
}
return $out;
}
else
{
return array();
}
}
here you go mate.
<?php
$array = ["1","2","5-10","15-20"];
$newArr = array();
foreach($array as $item){
if(strpos($item, "-")){
$temp = explode("-", $item);
$first = (int) $temp[0];
$last = (int) $temp[1];
for($i = $first; $i<=$last; $i++){
array_push($newArr, $i);
}
}
else
array_push($newArr, $item);
}
print_r($newArr);
?>
Simpler and shorter answer.
See in Ideone
$new_array = array();
foreach($array as $number){
if(strpos($number,'-')){
$range = explode('-', $number);
$new_array = array_merge($new_array, range($range[0],$range[1]));
}
else{
$new_array[] = (int) $number;
}
}
var_dump($new_array);
try this:
$array = ["1","2","5-10","15-20"];
$result = [];
foreach ($array as $a) {
if (strpos($a,"-")!== false){
$tmp = explode("-",$a);
for ($i = $tmp[0]; $i<= $tmp[1]; $i++) $result[] = $i;
} else {
$result[] = $a;
}
}
var_dump($result);
you did not finish a little
$array = ["1","2","5-10","15-20"];
// need to reverse order else index will be incorrect after inserting
$rangeArray = array_reverse( preg_grep('[-]',$array), true);
$convertedArray = $array;
foreach($rangeArray as $index=>$value) {
$rangeVal = explode('-',$value);
array_splice($convertedArray, $index, 1, range($rangeVal[0],$rangeVal[1]));
}
print_r($convertedArray);
I need to find not just duplicates in an array, but numbers that are within 1 of each other.
example: $myArr = array(46,78,77,43,86,1,47,14,51,31)
How would I get find those numbers if there no duplicates were found?
Thanks.
This will work - tested:
$myArr = array(46,78,77,43,86,1,47,14,51,31);
$i = 1;
while($i <= 99){
if(in_array($i, $myArr)){
// This means it's in the array
// Let's see if it's +1 of the last #
if(isset($last_num)){
$res = ($i + 1);
if(in_array($res, $myArr)){
echo $res . ' is in the array<br>';
}
}
}
$last_num = $i;
$i++;
}
Could use something like this.
<?
$haystack = array(31,46,78,77,43,86,1,47,14,51,31);
array_walk($haystack, function($key, $value) use ($haystack) {
$needle = array($key - 1, $key, $key + 1);
$r = array_intersect($haystack, $needle);
if(count($r) > 1) { unset($r[$value]); print_r(array_values($r)); }
});
?>
Or if you want them returned in an array:
<?
$haystack = array(31,46,78,77,43,86,1,47,14,51,31);
$result = array_filter(array_map(function($key, $value) use ($haystack) {
$needle = array($key - 1, $key, $key + 1);
$r = array_intersect($haystack, $needle);
if(count($r) > 1) { unset($r[$value]); return array_values($r)['0']; }
}, $haystack));
print_r($result);
?>
A little more verbose, but it may be more efficient since we're only looping through the array when necessary. It will return the keys of the original array where duplicates and values within range are found. (Note: I've expanded the code out a lot more than I normally would just for readability for OP)
/**
* Find the any values within an array that are within
* the specified range from another value.
*
* #param Array Array to search in
* #param uint Unsigned integer used for comparison
* #return Array The keys of all found values
**/
function findWithinRange(Array $array, $range) {
// sort the array values numerically
// so we don't have to loop through
// the entire array for each check
asort($array, SORT_NUMERIC);
// Keep the keys in case it's an associative array
$keys = array_keys($array);
// Get the values without the keys so we can easily loop
$values = array_values($array);
$return = array();
// Loop over each item in the array
foreach( $values as $k => $v ) {
$start = $k;
$min = $v - $range;
$max = $v + $range;
// track backwards in the array until we're less than range
// We could use array_search, but we'd be calling it multiple times
// This only runs through the array once and dies the moment
// it is out of the specified range
while(true) {
$k--;
if( !isset($values[$k]) ) {
break; // don't continue if we run out of keys
}
$curVal = $values[$k];
if( $curVal >= $min ) {
$return[] = $keys[$k];
}
else {
break; // kill the while loop if we're outside of range
}
}
// reset
$k = $start;
// track forward in the array until we're greater than range
while(true) {
$k++;
if( !isset($values[$k]) ) {
break; // don't continue if we run out of keys
}
$curVal = $values[$k];
if( $curVal <= $max ) {
$return[] = $keys[$k];
}
else {
break; // kill the while loop if we're outside of range
}
}
}
// drop duplicate reports
$return = array_unique($return);
// return all found keys
return $return;
}
Example usage:
$myArr = array(46,78,77,43,86,1,47,14,51,31);
$res = findWithinRange($myArr, 1);
var_export($res);
// array(6, 0, 1, 2)
I have this loop and im wondering how can i get the MIN and MAX value inside the loop:
foreach($result_1 as $key_1) {
if($key_1->ordering > $key_0->ordering ) {
echo $key_1->ordering;
}
}
RESULT : 234
RESULT WANTED IS MIN (2) AND MAX (4) VALUES
Sounds like a good job for the functional reduce approach. You can do this in PHP with the array_reduce function:
You pass in an array, a callback and a starting value and the function will call the callback with the current value and the next item from the array and store the result.
php> $array = [ 6, 2, 8, 4 ];
array (
0 => 6,
1 => 2,
2 => 8,
3 => 4,
)
php> array_reduce($array, 'min', reset($array));
int(2)
php> array_reduce($array, 'max', reset($array));
int(8)
In this example I used min and max respectively as the callback and the first array item as the starting value.
In order to use this properly on your array you can pass in a custom callback using an anonymous function:
function ($a, $b) {
return max($a->ordering, $b->ordering);
}
You just need to loop through the array once and check every value against the current minimum/maximum, and replace it if it is smaller/bigger.
$min = reset( $array )->ordering; // Assign any value to start (just the first in this case)
$max = reset( $array )->ordering; // Assign any value to start (just the first in this case)
foreach ( $array as $object ) {
//max
if( $object->ordering > $max ) {
$max = $object->ordering;
}
//min
if( $object->ordering < $min ) {
$min = $object->ordering;
}
}
echo $min;
echo $max;
Just use the min($result_1) and max($result_1) functions that are built into PHP.
http://us2.php.net/max
http://us2.php.net/min
Edit:
Since it's an array of objects, try using two temporary variables to keep track of the min and max. I'm assuming in this code you're looking for the max and min ordering.
$min = 1000000;
$max = -1000000;
foreach($result_1 as $key_1) {
if($key_1->ordering > $max ) {
$max = $key_1->ordering;
}
else if($key_1->ordering < $min) {
$min = $key_1->ordering;
}
}
echo $min;
echo $max;
You can take the logic of a selection sort and use it to find the minimum value. I'm sure you can figure out from this code how to find the max.
$min = 0;
foreach($result_1 as $key_1) {
$min = $key_1->ordering
foreach($result_1 as $key_2) {
if($min > $key_2->ordering) {
$min = $key_2->ordering;
}
}
}
Here is my test:
$data = array(
5,
6,
7,
1,
9,
11,
3
);
$min = 0;
foreach($data as $key => $value) {
$min = $value;
foreach($data as $key2 => $value2) {
if($min > $value2) {
$min = $value2;
}
}
}
echo $min . "\n"; // 1
I have an array that has been sorted from low to high which has over 260k values in. I have found out the mean(average) and median of the array just need to find out the mode?
I cannot use any mathematical functions that PHP has, it has to be all done manually.
I would like it so there could be just one value that is the mode but then there can be multiple values that can be the mode. I also need to be able to record the number of times that the value is stored. For example the number 51 appears 6 times so I can print both values.
This is my code so far:
$amountRecords = 0;
$totalValue = 0;
$valueArray = array();
// reads in csv file
$handle = fopen('Task1-DataForMeanMedianMode.csv', 'r');
// to skip the header names/values
fgetcsv($handle);
// creates array containing variables of csv file in ascending order
while(($row = fgetcsv($handle, "\r")) != FALSE)
{
// if amountRecords equals 0
if($amountRecords == 0)
{
// adds value from csv to array
$valueArray[] = $row[1];
} // else amountRecords does not equal 0
else
{
// if the value in array location before is greater than the current value from the csv file
if($valueArray[$amountRecords - 1] > $row[1])
{
// the current array location becomes the one in the location before
$valueArray[] = $valueArray[$amountRecords - 1];
// add the value from the csv to the location before
$valueArray[$amountRecords - 1] = $row[1];
} // if the value in the location before is not greater than the current value in the csv file
else
{
// adds value from csv to array
$valueArray[] = $row[1];
}
}
// calculates the total value of the values in csv file
$totalValue = $totalValue + $row[1];
// calculates the number of values in the csv file
$amountRecords++;
}
// calculate average value of payments
$averageValue = $totalValue / $amountRecords;
// limit integer to 2 decimal place
$average = number_format($averageValue,2,'.','');
// finds middle value
$middle = floor(($amountRecords / 2) - 1);
// calculates the median value
// if array size is even
if($amountRecords % 2 == 0)
{
// calculates median
$median = $valueArray[$middle];
}
else // if array size is odd
{
// calculate low and high values
$low = $valueArray[$middle];
$high = $valueArray[$middle + 1];
// calculates median
$median = (($low + $high) / 2);
}
// works out mode
// creates array count
$count = array();
// for each value in the valueArray
foreach( $valueArray as $value )
{
if( isset( $count[$value] ))
{
$count[$value]++;
}
else
{
$count[$value] = 1;
}
}
$mostCommon = "";
$iter = 0;
foreach( $count as $k => $v )
{
if( $v > $iter )
{
$mostCommon = $k;
$iter = $v;
}
}
$modeArray = array( "mode" => $mostCommon , "count" => $iter );
The mode of a numerical set is the number that occurs the most often. You can do this with PHP using code similar to the following:
$values = array_count_values($valueArray);
$mode = array_search(max($values), $values);
Simple!
$arr = array(4,6,7,1,4,7,4,7,1);
$freq = array();
for($i=0; $i<count($arr); $i++)
{
if(isset($freq[$arr[$i]])==false)
{
$freq[$arr[$i]] = 1;
}
else
{
$freq[$arr[$i]]++;
}
}
$maxs = array_keys($freq, max($freq));
for($i=0; $i<count($maxs); $i++)
{
echo $maxs[$i] . ' ' . $freq[$maxs[$i]];
echo '<br />';
}
Mathematical only solution:
//sample data
$dataArr = ["1", "3", "5", "1", "3", "7", "1", "8", "1"];
//a multidimensional array to hold the keys (extracted fro above) and their values (number of occurrences)
$multiDArr = [];
for ($i = 0; $i < count($dataArr); $i++) {
$key = $dataArr[$i];
if (isset($multiDArr[$key])) {
//key already exists; increment count of its value
$multiDArr[$key] = $multiDArr[$key] + 1;
} else {
//key does nto exist; add it and an inital value of 1
$multiDArr[$key] = 1;
}
}
$highestOccuring = 0;
$highestOccuringKey = null;
foreach ($multiDArr as $key => $value) {
if ($value > $highestOccuring) {
$highestOccuring = $value;
$highestOccuringKey = $key;
}
}
echo "MODE / highest occuring key: " . $highestOccuringKey;
/** find array mode, most often see value
* #param list(int) $a_in
* #return list(int)
*/
function array_mode(array $a_in): array{
$a_freq = [];
foreach( $a_in as $v ) {
if (!isset($a_freq[$v])) {
$a_freq[$v] = 0;
}
$a_freq[$v]++;
}
$a_maxs = array_keys($a_freq, max($a_freq));
return $a_maxs;
}
// test code
$a_in = [4,6,7,1,4,7,4,7,1];
array_mode( $a_in);
This will take values and turn it into an array of the modes. For Example: print_r(get_mode(1,2,2,3,3,3,4,4,5,5,5,6,7,8,9)); will return,
Array
(
[0] => Array
(
[value] => 3
[count] => 3
)
[1] => Array
(
[value] => 5
[count] => 3
)
)
code:
function get_mode(...$inputArray){
$max=0;
return array_reduce(
array_values(array_reduce(array_values($inputArray),function($talliedArray,$inputNode){
if(isset($talliedArray[(string)$inputNode]))
$talliedArray[(string)$inputNode]['count']++;
else
$talliedArray[(string)$inputNode] = [
'value' => $inputNode,
'count' => 1
];
return $talliedArray;
},[])),function($modeArray,$talliedNode)use(&$max){
if($talliedNode['count'] < $max) return $modeArray;
if($talliedNode['count']=== $max) return array_merge($modeArray,[$talliedNode]);
//if count > $max
$max = $talliedNode['count'];
return [$talliedNode];
},[]);
}
This satisfies the "no math functions", the "multiple return modes" and the "have the value and number of occurrences returned".
This will only really work with strings and numbers. It will go weird with booleans, Objects and Arrays.