Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP merge two arrays on the same key AND value

Tags:

arrays

php

I have two arrays. And I want to merge them on the same key AND value. If they have the same ur_user_id then they are merged. array2 only provides some additional data for array1, so the new_array.length = array1.length. array1 just gets the additional data from array2.

$array1 =    
    array(
        array('ur_user_id'=> 1,'ur_fname'=>'PerA','ur_lname'=>'SonA'),
        array('ur_user_id'=> 2,'ur_fname'=>'PerB','ur_lname'=>'SonB'),
        array('ur_user_id'=> 3,'ur_fname'=>'PerC','ur_lname'=>'SonC'),
    );
$array2 = 
    array(
        array('ur_user_id' => 5,'ur_code' => 'EE','ur_user_role' => 'testE'),
        array('ur_user_id' => 4,'ur_code' => 'DD','ur_user_role' => 'testD'),
        array('ur_user_id' => 6,'ur_code' => 'FF','ur_user_role' => 'testF'),
        array('ur_user_id' => 3,'ur_code' => 'CC','ur_user_role' => 'testC'),
        array('ur_user_id' => 1,'ur_code' => 'AA','ur_user_role' => 'testA'),
        array('ur_user_id' => 2,'ur_code' => 'BB','ur_user_role' => 'testB'),
    );    

Then the new array must look like this. It will have both the values from the array1 and array2.

$new_array =    
    array(
        array('ur_user_id'=> 1,'ur_fname'=>'PerA','ur_lname'=>'SonA','ur_code' => 'AA','ur_user_role' => 'testA'),
        array('ur_user_id'=> 2,'ur_fname'=>'PerB','ur_lname'=>'SonB','ur_code' => 'BB','ur_user_role' => 'testB'),
        array('ur_user_id'=> 3,'ur_fname'=>'PerC','ur_lname'=>'SonC','ur_code' => 'CC','ur_user_role' => 'testC'),
    );

The array1.length is always less than or equal to array2.length never greater. And the order of both arrays will not be always ordered. I've tried the function below which I got somewhere here but it doesn't work for me and I'm not really good with loops.

function merge_common_keys(){
    $arr = func_get_args();
    $num = func_num_args();

    $keys = array();
    $i = 0;
    for ($i=0; $i<$num; ++$i){
        $keys = array_merge($keys, array_keys($arr[$i]));
    }
    $keys = array_unique($keys);

    $merged = array();

    foreach ($keys as $key){
        $merged[$key] = array();
        for($i=0; $i<$num; ++$i){
            $merged[$key][] = isset($arr[$i][$key]) ? $arr[$i][$key] : null;
        }
    }
    return $merged;
}

Based on the given arrays the result is like this. It only merges on the same key.

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [ur_user_id] => 1
                    [ur_fname] => PerA
                    [ur_lname] => SonA
                )

            [1] => Array
                (
                    [ur_user_id] => 5
                    [ur_code] => AA-BB-CC
                    [ur_user_role] => testE
                )

        )
like image 295
Dev Avatar asked Oct 18 '22 09:10

Dev


1 Answers

When you need to make iterated checks/searches for values (effectively a unique identifier), the best performing approach will often:

  1. generate a keyed array and
  2. make iterated calls of isset() (instead of in_array() or array_search())

ur_user_id is your "unique identifier".
$array2 is prepared by assigning ur_user_id values as keys with array_column().
$array1 controls the number of iterations.
My approach will check for a corresponding row between $array1 and $array2 (to avoid Notices) before using a union operator (+=) to append the $array2 data to each original row of $array1.
The & in the foreach loop "modifies by reference" -- this means the actual input array is being "dealt with" instead of a copy of the input array.

Code: (Demo)

$array1 =    
    array(
        array('ur_user_id'=> 1,'ur_fname'=>'PerA','ur_lname'=>'SonA'),
        array('ur_user_id'=> 2,'ur_fname'=>'PerB','ur_lname'=>'SonB'),
        array('ur_user_id'=> 3,'ur_fname'=>'PerC','ur_lname'=>'SonC'),
    );
$array2 = 
    array(
        array('ur_user_id' => 5,'ur_code' => 'EE','ur_user_role' => 'testE'),
        array('ur_user_id' => 4,'ur_code' => 'DD','ur_user_role' => 'testD'),
        array('ur_user_id' => 6,'ur_code' => 'FF','ur_user_role' => 'testF'),
        array('ur_user_id' => 3,'ur_code' => 'CC','ur_user_role' => 'testC'),
        array('ur_user_id' => 1,'ur_code' => 'AA','ur_user_role' => 'testA'),
        array('ur_user_id' => 2,'ur_code' => 'BB','ur_user_role' => 'testB'),
    );  

$keyed = array_column($array2, NULL, 'ur_user_id'); // replace indexes with ur_user_id values

foreach ($array1 as &$row) {       // write directly to $array1 while iterating
    if (isset($keyed[$row['ur_user_id']])) { // check if shared key exists
        $row += $keyed[$row['ur_user_id']]; // append associative elements
    }
}

var_export($array1);

Output:

array (
  0 => 
  array (
    'ur_user_id' => 1,
    'ur_fname' => 'PerA',
    'ur_lname' => 'SonA',
    'ur_code' => 'AA',
    'ur_user_role' => 'testA',
  ),
  1 => 
  array (
    'ur_user_id' => 2,
    'ur_fname' => 'PerB',
    'ur_lname' => 'SonB',
    'ur_code' => 'BB',
    'ur_user_role' => 'testB',
  ),
  2 => 
  array (
    'ur_user_id' => 3,
    'ur_fname' => 'PerC',
    'ur_lname' => 'SonC',
    'ur_code' => 'CC',
    'ur_user_role' => 'testC',
  ),
)
like image 149
mickmackusa Avatar answered Oct 21 '22 05:10

mickmackusa