phparraysmultidimensional-arrayarray-mergemerging-data

Merge associative row data in a 2d array based on a column value


I need to merge the row data of my 2d array where rows share the same messageID value.

$myarray = [
    [
        'messageId' => '5ACE9D8841',
        'sender' => 'john@doe.com'
    ],
    [
        'messageId' => '7EE67D8170',
        'sender' => 'dan@doe.com'
    ],
    [
        'messageId' => '8095FD8836',
        'sender' => 'cat@doe.com'
    ],
    [
        'messageId' => '7EE67D8170',
        'dest' => 'mitch@doe.com',
        'status' => 'sent',
        'date' => '2021-02-01 11:06:55'
    ]
];

From the sample data, rows [1] and [3] are merged into [1] because they share the same [messageId]. Expected result:

Array
(
    [0] => Array
        (
            [messageId] => 5ACE9D8841
            [sender] => john@doe.com
        )

    [1] => Array
        (
            [messageId] => 7EE67D8170
            [dest] => mitch@doe.com
            [status] => sent
            [date] => 2021-02-01 11:06:55
            [sender] => dan@doe.com
        )

    [2] => Array
        (
            [messageId] => 8095FD8836
            [sender] => cat@doe.com
        )
)

I don't mind about the key index or the order.

EDIT : I've tried array_merge, array_merge_recursive and many others. Best result was obtained with

$result_arr = array();
foreach ($myarray as $sub_arr) {
    $result_arr = array_merge($result_arr, $sub_arr);
    $result_arr = array_unique($result_arr);
} 

It works but returns only the last iteration:

Array (
    [messageId] => 7EE67D8170
    [dest] => mitch@doe.com
    [status] => sent
    [date] => 2021-02-01 11:06:55
    [sender] => dan@doe.com
)

Solution

  • Try using array_reduce function with callback function:

    $result = array_values(array_reduce($myarray, function($rows, $item){
        if (array_key_exists('messageId', $item) && is_scalar($item['messageId'])) {
            $rows = array_replace_recursive($rows ?? [], [$item['messageId'] => $item]);
        }
        return $rows;
    }));
    
    print_r($result);
    

    fiddle