Search code examples
phparray-merge

How to merge an array on matching keys while adding the numerical values of others


My first post here even though I've been gathering knowledge from you guys from years. I'm trying to merge the following array where the names match, but I need to add the hours together.
Everything I try gives crazy results or gives errors I can't find answers to.

Example array:

Array (
    [0] => Array (
        [name] => Hunter
        [hours] => 4.00 )
    [1] => Array (
        [name] => Hunter
        [hours] => 4.00 )
    [2] => Array (
        [name] => Leon
        [hours] => 8.00 )
    [3] => Array (
        [name] => Rowdy
        [hours] => 8.00 )
    [4] => Array (
        [name] => Hunter
        [hours] => 8.00 )
    [5] => Array (
        [name] => Lonnie
        [hours] => 8.00 )
    [6] => Array (
        [name] => Leon
        [hours] => 8.00 )
    [7] => Array (
        [name] => Gavin
        [hours] => 8.00 )
    )

Desired Result:

Array (
    [0] => Array (
        [name] => Hunter
        [hours] => 16.00 )
    [1] => Array (
        [name] => Leon
        [hours] => 16.00 )
    [2] => Array (
        [name] => Rowdy
        [hours] => 8.00 )
    [3] => Array (
        [name] => Lonnie
        [hours] => 8.00 )
    [4] => Array (
        [name] => Gavin
        [hours] => 8.00 )
    )

This code works... kind of... It adds the first instance of a name twice. Thus giving hunter an extra 4 hours. It also doesn't remove the duplicate name/hour data.

I was going to add array_pop($php_data_array) above break; but that throws an error: Fatal error: Uncaught TypeError: Cannot access offset of type string on string which I don't understand why. (Adding any code inside the "if" throws that error)

while($entries=mysqli_fetch_assoc($get_time_sheets))
{
  $php_data_array[] = $entries; // Adding to array
  foreach($php_data_array as &$value){
        if($value['name'] === $entries['name']){
            $value['hours'] = $value['hours'] + $entries['hours'];
            break; // Stop the loop after we've found the item
        }
    }
}

Any help would be greatly appreciated! I'm probably overlooking something simple here and just don't see it.


Solution

  • Here you go, the script below will foreach your array and rebuild it as you have requested by looping through the array and building an array using name as the index, every time it hits the same name it will add the hours together until the loop ends. Then it will remove the indexes and default back to numbered indexes for the resulting array:

    $inputArray = [
        ['name' => 'Hunter', 'hours' => 4.00],
        ['name' => 'Hunter', 'hours' => 4.00],
        ['name' => 'Leon', 'hours' => 8.00],
        ['name' => 'Rowdy', 'hours' => 8.00],
        ['name' => 'Hunter', 'hours' => 8.00],
        ['name' => 'Lonnie', 'hours' => 8.00],
        ['name' => 'Leon', 'hours' => 8.00],
        ['name' => 'Gavin', 'hours' => 8.00],
    ];
    
    $result = [];
    
    foreach ($inputArray as $entry) {
        $name = $entry['name'];
        $hours = $entry['hours'];
    
        if (isset($result[$name])) {
            $result[$name]['hours'] += $hours;
        } else {
            $result[$name] = ['name' => $name, 'hours' => $hours];
        }
    }
    
    $result = array_values($result);
    
    print_r($result);
    

    Result:

    Array
    (
        [0] => Array
            (
                [name] => Hunter
                [hours] => 16
            )
    
        [1] => Array
            (
                [name] => Leon
                [hours] => 16
            )
    
        [2] => Array
            (
                [name] => Rowdy
                [hours] => 8
            )
    
        [3] => Array
            (
                [name] => Lonnie
                [hours] => 8
            )
    
        [4] => Array
            (
                [name] => Gavin
                [hours] => 8
            )
    
    )