imperium2335
imperium2335

Reputation: 24122

Average columns in PHP

I have a series of columns (Jan, Feb, Mar, etc) and I want to average the values of each column for each row however many there may be.

I have:

protected function generateAverage($staff, $type)
{
    $months = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
    $staff = array_map(function ($row) use ($type) {
        if ($row['row_type'] == $type) {
            return $row;
        }
    }, $staff);

    foreach ($staff as $key => $employee) {
        $months[0] += $employee['amounts'][0];
        $months[1] += $employee['amounts'][1];
        $months[2] += $employee['amounts'][2];
        $months[3] += $employee['amounts'][3];
        $months[4] += $employee['amounts'][4];
        $months[5] += $employee['amounts'][5];
        $months[6] += $employee['amounts'][6];
        $months[7] += $employee['amounts'][7];
        $months[8] += $employee['amounts'][8];
        $months[9] += $employee['amounts'][9];
        $months[10] += $employee['amounts'][10];
        $months[11] += $employee['amounts'][11];
    }
    $months = array_map(function ($value) use ($staff) {
        return $value / (count($staff) / 2);
    }, $months);
    $months[] = array_sum($months);
    return $months;
}

Here is a sample of the data that goes into the above function:

array:6 [
  0 => array:4 [
    "amounts" => array:13 [
      0 => "30000.00"
      1 => "30000.00"
      2 => "30000.00"
      3 => "30000.00"
      4 => "30000.00"
      5 => "30000.00"
      6 => "30000.00"
      7 => "30000.00"
      8 => "30000.00"
      9 => "30000.00"
      10 => "30000.00"
      11 => "30000.00"
      12 => 360000.0
    ]
    "image" => "test.jpg"
    "row_name" => "Target"
    "row_type" => "target"
  ]
...

Usage:

$data['aggregates']['Target average'] = $this->generateAverage(array_values($data['staff']), 'target');

I feel the way the average is calculated is messy, is there a better way to do this?

Upvotes: 0

Views: 290

Answers (3)

PHPer
PHPer

Reputation: 674

I think you can consider using array_colum,

1) array_column makes an array of all the values in a particular index position in a row

$column1 =  array_column($employee, 0 );
$column2 =  array_column($employee, 1 );
$column3 =  array_column($employee, 2 );
.
.
.

2)Get the column count by count($columnX), where X is the index of the column

3) Using (1) and (2) calculate the average as needed

Upvotes: 0

NDM
NDM

Reputation: 6830

A couple of small footprint reductions

protected function generateAverage($staff, $type)
{
    // create 12 months with 0 value
    $months = array_fill(0, 12, 0);
    // use array_filter instead of map
    $staff = array_filter(function ($row) use ($type) {
        return $row['row_type'] === $type;
    }, $staff);
    // do count outside loop
    $staffCount = count($staff);
    // loop employees and add up each month, dividing early
    foreach ($staff as $employee) {
        for ($i = 0; $i < 12; $i++) {
            $months[$i] += $employee['amounts'][$i] / $staffCount;
        }
    }
    return $months;
}

I dont know why you are dividing the staff count by 2 or why you are summing in the end, my function just gives an average per month.

Upvotes: 1

Alexey Mezenin
Alexey Mezenin

Reputation: 163898

Since you're using Laravel, most of the data you work with is collections. So, before converting a collection into an array, you could use avg() helper:

$collection->avg($key);

Upvotes: 0

Related Questions