Question

I have this code

$a1 = array(
    'success'    => TRUE,
    'data'       => array(
        'foo' =>
        array(
            21 =>
            array(
                1 =>
                array(1, 2, 3, 4, 5)
            )
        )
    )
);

$a2 = array(
    'success'    => TRUE,
    'data'       => array(
        'foo' =>
        array(
            21 =>
            array(
                7 =>
                array(6, 7, 8, 9, 10)
            )
        )
    )
);

$results = array();
$results = array_merge_recursive($results, $a1['data']);
$results = array_merge_recursive($results, $a2['data']);
var_dump($results);

From what I understood of array_merge_recursive(), I am expecting the results would be

array
  'foo' => 
    array
      21 => 
        array
          1 => 
            array
              0 => int 1
              1 => int 2
              2 => int 3
              3 => int 4
              4 => int 5
           7 =>
              0 => int 6
              1 => int 7
              2 => int 8
              3 => int 9
              4 => int 10

Instead I get this

array
  'foo' => 
    array
      21 => 
        array
          1 => 
            array
              0 => int 1
              1 => int 2
              2 => int 3
              3 => int 4
              4 => int 5
      22 => 
        array
          7 => 
            array
              0 => int 6
              1 => int 7
              2 => int 8
              3 => int 9
              4 => int 10

Where did the 22 index come from? Why is it outputting differently? Did I use the function wrong?

Was it helpful?

Solution

array_merge_recursive merges elements/arrays from the same depth as the first array, but if both arrays the key is a numerical index and they are the same it then appends to it. This is what is happening in your situation. since then your array is appended at 2nd level where index 21 is found by creating index 22. To receive the desired output you have change your index 21 to a string key like "x21"

Notes from php manual

If the input arrays have the same string keys, then the values for these keys are merged together into an array, and this is done recursively, so that if one of the values is an array itself, the function will merge it with a corresponding entry in another array too. If, however, the arrays have the same numeric key, the later value will not overwrite the original value, but will be appended.

OTHER TIPS

I just came across the same issue, I wanted to merge the arrays but surprisingly found the keys were changed automatically in the result. The reason was because my "keys" are string of decimal numbers, without any alphabetic characters.

But luckily I noticed that if the keys have alphabetic characters, they could be reserved. So just came up with the following idea, which would append a letter 'S' to each key recursively before the merge, and later remove it in the final result.

Please refer to the enhanced_array_merge_recursive function for details:

<?php

$aa = [
  '10' => 'book',
  '14' => ['cat'],
];

$ab = [
  '12' => 'cd',
  '18' => 'cup',
  '14' => ['dog'],
];

var_dump(enhanced_array_merge_recursive($aa, $ab));

function revise_keys($source)
{
    if (!is_array($source)) {
        return $source;
    }

    $target = [];

    foreach ($source as $key => $value) {
        $target['S' . $key] = revise_keys($value);
    }

    return $target;
}

function revert_keys($source)
{
    if (!is_array($source)) {
        return $source;
    }

    $target = [];

    foreach ($source as $key => $value) {
        $target[substr($key, 1 - strlen($key))] = revert_keys($value);
    }

    return $target;
}

function enhanced_array_merge_recursive(...$candidates)
{
    $merged = [];

    foreach ($candidates as $candidate) {
        if (!is_array($candidate)) {
            continue;
        }

        $merged = array_merge_recursive($merged, revise_keys($candidate));
    }

    return revert_keys($merged);
}

Output looks like following:

array(4) {
  [10] =>
  string(4) "book"
  [14] =>
  array(1) {
    [0] =>
    array(2) {
      [0] =>
      string(3) "cat"
      [1] =>
      string(3) "dog"
    }
  }
  [12] =>
  string(2) "cd"
  [18] =>
  string(3) "cup"
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top