How to find the mode of an array in PHP

Viewed 12560

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 );
5 Answers

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.

Related