PHP multidimensional array, average of duplicate values

276 views Asked by At

I'm trying to insert high level product review data to SKU records but am stuck with trying to get the average value of duplicated keys.

Array
(
    [0] => Array
        (
            [sku] => 70835
            [rating] => 5
        )

    [1] => Array
        (
            [sku] => F6W/35
            [rating] => 5
        )

    [2] => Array
        (
            [sku] => 36865
            [rating] => 5
        )

    [3] => Array
        (
            [sku] => 36835
            [rating] => 5
        )

    [4] => Array
        (
            [sku] => F30W/T8/830/POLYLUX
            [rating] => 2
        )

    [5] => Array
        (
            [sku] => 70835
            [rating] => 4
        )
)

I would like to get the average rating for the duplicate skus so expected output would be:

Array
(
    [0] => Array
        (
            [sku] => 70835
            [rating] => 4.5
        )

    [1] => Array
        (
            [sku] => F6W/35
            [rating] => 5
        )

    [2] => Array
        (
            [sku] => 36865
            [rating] => 5
        )

    [3] => Array
        (
            [sku] => 36835
            [rating] => 5
        )

    ...
)

I have the below loop which is summing the duplicates but I'm struggling to get the average

foreach ($reviews as $val) {
    if (!isset($result[$val['sku']]))
    {
        $result[$val['sku']] = $val;
    }
    else{
        $result[$val['sku']]['rating'] += $val['rating'];
        #This will sum the duplicated ratings but I need to divide the sum here by the number of times the 'sku' index was duplicated so in the example 9/2 = 4.5
    }
}

thanks in advance!

3

There are 3 answers

2
steven On BEST ANSWER

What about adding a count field to your result array...

foreach ($reviews as $val) {
    if (!isset($result[$val['sku']]))
    {
        $result[$val['sku']] = $val;
        $result[$val['sku']]["count"] = 1;
    }
    else{
        $result[$val['sku']]['rating'] += $val['rating'];
        $result[$val['sku']]["count"] ++;
    }
}

foreach($result as $k => $v) {
    $result[$k]['avg'] = $v['rating']/$v['count'];
}
2
Blue On

This should work for you:

foreach ($reviews as $val) {
    if (!isset($result[$val['sku']]))
    {
        $result[$val['sku']] = array('rating' => $val['rating'], 'count' => 1);
    }
    else{
        $result[$val['sku']]['rating'] += $val['rating'];
        $result[$val['sku']]['count']++;
    }
}

foreach ($result as &$val) {
    $val['average'] = $val['rating'] / $val['count'];
}

Be aware, if this data is coming from a database, there are much easier ways to do this, by using GROUP BY statements.

2
Akshay Hegde On
[akshay@localhost tmp]$ cat test.php
<?php

$array = array (
  0 => 
  array (
    'sku' => '70835',
    'rating' => '5',
  ),
  1 => 
  array (
    'sku' => 'F6W/35',
    'rating' => '5',
  ),
  2 => 
  array (
    'sku' => '36865',
    'rating' => '5',
  ),
  3 => 
  array (
    'sku' => '36835',
    'rating' => '5',
  ),
  4 => 
  array (
    'sku' => 'F30W/T8/830/POLYLUX',
    'rating' => '2',
  ),
  5 => 
  array (
    'sku' => '70835',
    'rating' => '4',
  ),
);

$final=$count=array();

foreach($array as $v)
{
    if(isset($final[$v['sku']]))
    {
      $final[$v['sku']]['rating'] += $v['rating'];
      $count[$v['sku']]++;
    }else
    {
      $final[$v['sku']] = $v;
      $count[$v['sku']] = 1;
    }

}

array_map( function($a, $b) use (&$final){ $final[$a]['rating']/=$b; }, array_keys($count),array_values($count));
unset($count);

// Input
print_r($array);

// Output
print_r( array_values($final));

?>

Output

[akshay@localhost tmp]$ php test.php
Array
(
    [0] => Array
        (
            [sku] => 70835
            [rating] => 5
        )

    [1] => Array
        (
            [sku] => F6W/35
            [rating] => 5
        )

    [2] => Array
        (
            [sku] => 36865
            [rating] => 5
        )

    [3] => Array
        (
            [sku] => 36835
            [rating] => 5
        )

    [4] => Array
        (
            [sku] => F30W/T8/830/POLYLUX
            [rating] => 2
        )

    [5] => Array
        (
            [sku] => 70835
            [rating] => 4
        )

)
Array
(
    [0] => Array
        (
            [sku] => 70835
            [rating] => 4.5
        )

    [1] => Array
        (
            [sku] => F6W/35
            [rating] => 5
        )

    [2] => Array
        (
            [sku] => 36865
            [rating] => 5
        )

    [3] => Array
        (
            [sku] => 36835
            [rating] => 5
        )

    [4] => Array
        (
            [sku] => F30W/T8/830/POLYLUX
            [rating] => 2
        )

)