RiotAct
RiotAct

Reputation: 773

Group row data in a 2d array and calculate average of a column in each group

There are similar questions on Stack Overflow but nothing quite like mine, and I also want to double check that I am doing this the most efficient way (resource wise).

I have surveys that are submitted and I want to tally the results. Each survey is saved in a multidimensional array like so:

Array ( [name] => Clark Kent [rating] => 5 )

These are coming from a loop as they are separate database entries.

So I am beginning by creating a new array with all these combined:

$mods = array();
$index = -1;
foreach($fields as $field) {
  $index++;
  $mods[$index]['name'] = $field['name'];
  $mods[$index]['rating'] = $field['rating'];
}

Then I am grouping these so that all the ratings for the same name are together, so I can sum them later.

$groups = array();
foreach ($mods as $value) {
  $groups[$value['name']][] = $value;
}

This produces the following:

Array ( 
  [Clark Kent] => Array (
    [0] => Array (
        [name] => Clark Kent
        [rating] => 5
        )
    [1] => Array (
        [name] => Clark Kent
        [rating] => 5
        )
    )
[Peter Parker] => Array (
    [0] => Array (
        [name] => Peter Parker
        [rating] => 5
        )
    [1] => Array (
        [name] => Peter Parker
        [rating] => 5
        )
    )
[Bruce Wayne] => Array (
    [0] => Array (
        [name] => Bruce Wayne
        [rating] => 5
        )
    [1] => Array (
        [name] => Bruce Wayne
        [rating] => 5
        )
    )
[Bruce Banner] => Array (
    [0] => Array (
        [name] => Bruce Banner
        [rating] => 5
        )
    [1] => Array (
        [name] => Bruce Banner
        [rating] => 5
        )
    )
)

What I am trying to accomplish would be something like this:

<table>
  <tr>
    <td>Clark Kent</td>
    <td>{average of all ratings}</td>
  </tr>
</table>

I'm most of the way there, but I am stuck! I'm not sure how to get the grouped name that doesn't have any type of index or key so I can use that value for my table. Then I need to sum each grouped values.

Upvotes: 2

Views: 1746

Answers (4)

amit rawat
amit rawat

Reputation: 783

Try to use the code below. Eliminating an extra loop to preparing group array.

$mods = array(); 
foreach($fields as $field) { 
  $mods[$field['name']][] = $field['rating']; 
}

<table>
  <tr>

<?php
if($mods) {
    foreach($mods as $key=>$value) {
?>
    <td><?php echo $key; ?></td>
    <td><?php echo (array_sum($value)/count($value)); ?></td> 
<?php 
    }
}
?>

Upvotes: 1

Frankich
Frankich

Reputation: 852

You could simplify the problem in the first place in the structure you are using to handle those date

foreach($fields as $field) {
     $mods[$field['name']][] = $field['rating'];
}

then just foreach with the key parameter

foreach($mods as $name => $mod) {
     echo $name;
     echo array_sum($mod) / count($mod);
}

Upvotes: 2

Nick
Nick

Reputation: 147146

I would do all the necessary math in the loop that reads the data from the database. Something like this:

$ratings = array();
while ($row = $result->fetch_assoc()) {
    $name = $row['name'];
    if (!isset($ratings[$name])) {
        $ratings[$name] = array('count' => 1, 'sum' => $row['rating']);
    }
    else {
        $ratings[$name]['count']++;
        $ratings[$name]['sum'] += $row['rating'];
    }
}

Then you can just output your table like so:

echo "<table>";
foreach ($ratings as $name => $r) {
    echo "<tr><td>$name</td><td>" . round($r['sum'] / $r['count'], 1) . "</td></tr>";
}
echo "</table>";

Upvotes: 5

u_mulder
u_mulder

Reputation: 54831

To get average you can do something like:

foreach ($groups as $name => $group) {
    $average = array_sum(array_column($group, 'rating')) / count($group);
    echo $name;
}

Upvotes: 2

Related Questions