Matthew Colley
Matthew Colley

Reputation: 11466

Recursively merge two multidimensional associative arrays and define new subarray keys according to their origin array

I am trying to merge the following two arrays into one array, sharing the same key:

$array1 = [
    ["Camera1" => "192.168.101.71"],
    ["Camera2" => "192.168.101.72"],
    ["Camera3" => "192.168.101.74"],
];

$array2 = [
    ["Camera1" => "VT"],
    ["Camera2" => "UB"],
    ["Camera3" => "FX"]
];

As you can see, they share the same key (Camera1, Camera2, Camera3, etc..)

Here is what I have tried:

$Testvar = array_merge($NewArrayCam, $IpAddressArray);
foreach ($Testvar as $Newvals) {
    $cam = array();
    foreach ($Newvals as $K => $V) {
        $cam[] = array($K => $V);
    }
}

My desired result:

[
    'Camera1' => [
        'ip' => '192.168.101.71',
        'name' => 'VT',
    ],
    'Camera2' => [
        'ip' => '192.168.101.72',
        'name' => 'UB',
    ],
    'Camera3' => [
        'ip' => '192.168.101.74',
        'name' => 'FX',
    ]
]

Upvotes: 8

Views: 81681

Answers (11)

mickmackusa
mickmackusa

Reputation: 48073

Spreading the two arrays inside of an array_merge_recursive() is an attractive tool, but there is no callback parameter to create the desired subarray keys. The input arrays need to be re-keyed/restructured in advance. With associative, non-numeric keys on all levels, subsequently merged arrays will be grouped appropriately regardless of their order. Demo

array_walk_recursive($array1, fn(&$v) => $v = ['ip' => $v]);

array_walk_recursive($array2, fn(&$v) => $v = ['name' => $v]);

var_export(
    array_merge_recursive(...$array1, ...$array2)
);

Or a fully nested approach:

var_export(
    array_merge_recursive(
        ...array_map(
            fn($sub) => [key($sub) => ['ip' => current($sub)]],
            $array1
        ),
        ...array_map(
            fn($sub) => [key($sub) => ['name' => current($sub)]],
            $array2
        )
    )
);

Output (from either):

array (
  'Camera1' => 
  array (
    'ip' => '192.168.101.71',
    'name' => 'VT',
  ),
  'Camera2' => 
  array (
    'ip' => '192.168.101.72',
    'name' => 'UB',
  ),
  'Camera3' => 
  array (
    'ip' => '192.168.101.74',
    'name' => 'FX',
  ),
)

Upvotes: 0

ii iml0sto1
ii iml0sto1

Reputation: 1762

You could convert all numeric keys to strings and use array_replace_recursive which:

merges the elements of one or more arrays together so that the values of one are appended to the end of the previous one. It returns the resulting array.

Example

$arr1 = [
    'rate' => 100   
];

$arr2 = [
    'rate' => 100,
    'name' => 'Best Name In Town',
];

print_r(array_replace_recursive($arr1, $arr2));

Output

Array
(
    [rate] => 100
    [name] => Best Name In Town
)

Upvotes: 0

Volodymyr Klyuka
Volodymyr Klyuka

Reputation: 81

For your nesting level will be enough this:

$sumArray = array_map(function ($a1, $b1) { return $a1 + $b1; }, $array1, $array2);

For deeper nesting it wont work.

Upvotes: 8

Erik Ieger Dobrychtop
Erik Ieger Dobrychtop

Reputation: 94

This worked for me. I joined two arrays with the same keys

$array1 = ArrayUtils::merge($array1, $array2);

If you need preserve NumericKey, use

$array1 = ArrayUtils::merge($array1, $array2, true);

Upvotes: 0

phvish
phvish

Reputation: 139

this would be one of the soluion:

function array_merge_custom($array1,$array2) {
    $mergeArray = [];
    $array1Keys = array_keys($array1);
    $array2Keys = array_keys($array2);
    $keys = array_merge($array1Keys,$array2Keys);

    foreach($keys as $key) {
        $mergeArray[$key] = array_merge_recursive(isset($array1[$key])?$array1[$key]:[],isset($array2[$key])?$array2[$key]:[]);
    }

    return $mergeArray;

}

$array1 = array(
    array("Camera1" => "192.168.101.71"),
    array("Camera2" => "192.168.101.72"),
    array("Camera3" => "192.168.101.74"),
);

$array2 = array(
    array("Camera1" => "VT"),
    array("Camera2" => "UB"),
    array("Camera3" => "FX")
);
echo '<pre>';
print_r(array_merge_custom($array1 , $array2));

Upvotes: 2

Prasanth Bendra
Prasanth Bendra

Reputation: 32820

Use array_merge_recursive :

Convert all numeric key to strings, (make is associative array)

$result = array_merge_recursive($ar1, $ar2);
print_r($result);

Ref : http://php.net/array_merge_recursive

Upvotes: 8

DrBeza
DrBeza

Reputation: 2251

Ideally I would look to format the two arrays in such a way that array_merge_recursive would simply merge the arrays without too much fuss.

However I did come up with a solution that used array_map.

$array1 = array(
    array("Camera1" => "192.168.101.71"),
    array("Camera2" => "192.168.101.72"),
    array("Camera3" => "192.168.101.74"),
);

$array2 = array(
    array("Camera1" => "VT"),
    array("Camera2" => "UB"),
    array("Camera3" => "FX")
);

$results = array();

array_map(function($a, $b) use (&$results) {

    $key = current(array_keys($a));
    $a[$key] = array('ip' => $a[$key]);

    // Obtain the key again as the second array may have a different key.
    $key = current(array_keys($b));
    $b[$key] = array('name' => $b[$key]);

    $results += array_merge_recursive($a, $b);

}, $array1, $array2);

var_dump($results);

The output is:

array (size=3)
  'Camera1' => 
    array (size=2)
      'ip' => string '192.168.101.71' (length=14)
      'name' => string 'VT' (length=2)
  'Camera2' => 
    array (size=2)
      'ip' => string '192.168.101.72' (length=14)
      'name' => string 'UB' (length=2)
  'Camera3' => 
    array (size=2)
      'ip' => string '192.168.101.74' (length=14)
      'name' => string 'FX' (length=2)

Upvotes: 11

HamZa
HamZa

Reputation: 14931

Something like this should work:

$array1 = array(array("Camera1" => "192.168.101.71"), array("Camera2" => "192.168.101.72"), array("Camera3" => "192.168.101.74"));
$array2 = array(array("Camera1" => "VT"), array("Camera2" => "UB"), array("Camera3" => "FX"));
$results = array();

foreach($array1 as $key => $array){
  foreach($array as $camera => $value){
    $results[$camera]['ip'] = $value;
  }
}

foreach($array2 as $key => $array){
  foreach($array as $camera => $value){
    $results[$camera]['name'] = $value;
  }
}
print_r($results);

Upvotes: 0

Sverri M. Olsen
Sverri M. Olsen

Reputation: 13283

The main problem are the arrays. Because of the way they are structured it becomes unnecessarily complicated to merge them. It they simply were normal associative arrays (i.e. array('Camera1' => 'VT') then it would be effortless to merge them.

I would suggest that you figure out how to format the data in such a way as to make it easier to work with.

This is a quick and dirty way of merging the two arrays. It takes one "camera" from one array, and then tries to find the corresponding "camera" in the other array. The function only uses the "cameras" in the $ips array, and only uses matching CameraN keys.

$ips = array(
    array('Camera1' => '192.168.101.71'),
    array('Camera2' => '192.168.101.72'),
    array('Camera3' => '192.168.101.74'),
);
$names = array(
    array('Camera1' => 'VT'),
    array('Camera2' => 'UB'),
    array('Camera3' => 'FX'),
);
function combineCameras($ips, $names) {
    $output = array();
    while ($ip = array_shift($ips)) {
        $ident = key($ip);
        foreach ($names as $key => $name) {
            if (key($name) === $ident) {
                $output[$ident] = array(
                    'name' => array_shift($name),
                    'ip' => array_shift($ip),
                );
                unset($names[$key]);
            }
        }
    }
    return $output;
}
var_dump(combineCameras($ips, $names));

Upvotes: 0

Emil Orol
Emil Orol

Reputation: 561

If both arrays have the same numbers of levels and keys this should work:

$array3 = array();

foreach ($array1 as $key1 => $value1) {
  // store IP
  $array3['Camera'.$key1]['IP'] = $value['Camera'.$key1]; 
  // store type of cam
  $array3['Camera'.$key1]['Type'] = $array2[$key]['Camera'.$key1]; 

}

At the end $array3 should be something like:

$array3 = array {

["Camera1"] => {['IP'] => "192.168.101.71", ['Type'] => "VT" }
["Camera2"] => {['IP'] => "192.168.101.72", ['Type'] => "UB" }
["Camera3"] => {['IP'] => "192.168.101.74", ['Type'] => "FX" }

}

Upvotes: 2

Peter Krejci
Peter Krejci

Reputation: 3192

Try to use array_merge_recursive.

Upvotes: 8

Related Questions