4

I'm sure there have been many questions like these in the past, so sorry if it's came up before. Basically, i'm trying to merge two multidimensional arrays whilst not creating 2 keys for any duplicate keys.

Here's an example:

$one = array(
    'foo' => array(
        'bar' => array(
            'hello' => 'world',
            'boom'  => 'universe'
        ),
        'whiz' => array(
            'wham' => array(
                'blam' => 'kaplow'
            )
        )
    )
);

$two = array(
    'foo' => array(
        'whiz' => 'woo',
        'king' => array(
            'kong' => 'animal'
        )
    )
);

If I was to use array_merge_recursive($one, $two); i'd get the following results:

array(1) {
  ["foo"]=>
  array(3) {
    ["bar"]=>
    array(2) {
      ["hello"]=>
      string(5) "world"
      ["boom"]=>
      string(8) "universe"
    }
    ["whiz"]=>
    array(2) {
      ["wham"]=>
      array(1) {
        ["blam"]=>
        string(6) "kaplow"
      }
      // This is the problem.
      [0]=>
      string(3) "woo"
    }
    ["king"]=>
    array(1) {
      ["kong"]=>
      string(6) "animal"
    }
  }
}

If I were to use array_merge($one, $two); i'd get the following results:

array(1) {
  ["foo"]=>
  array(2) {
    // This is good but the rest of the array is gone.
    ["whiz"]=>
    string(3) "woo"
    ["king"]=>
    array(1) {
      ["kong"]=>
      string(6) "animal"
    }
  }
}

Here's the output i'm after:

array(1) {
  ["foo"]=>
  array(3) {
    ["bar"]=>
    array(2) {
      ["hello"]=>
      string(5) "world"
      ["boom"]=>
      string(8) "universe"
    }
    // Key is replaced, rest of the array remains intact.
    ["whiz"]=>
    string(3) "woo"
    ["king"]=>
    array(1) {
      ["kong"]=>
      string(6) "animal"
    }
  }
}

So basically, i'm after the functionality of array_merge_recursive() but for it to also work like array_replace_recursive(), do you guys have any ideas?

--

I've accepted an answer for now, but don't be discouraged about showing any other possibly better methods, I will be checking back.

Thanks guys.

daryl
  • 14,307
  • 21
  • 67
  • 92
  • It'd help if you included what you actually expected as the output. The behavior of array_replace_recursive seems to be the most straight forward interpretation of the problem. – MatsLindh Jul 19 '12 at 13:20
  • This is not recursive, but wouldn't something like `$merged = $one['foo'] + $two['foo'];` work? – Stano Jul 19 '12 at 13:22
  • I updated for a better example. – daryl Jul 19 '12 at 13:28

1 Answers1

2

I think your looking for:

function farray_merge_recursive() {

    if (func_num_args() < 2) {
        trigger_error(__FUNCTION__ .' needs two or more array arguments', E_USER_WARNING);
        return;
    }
    $arrays = func_get_args();
    $merged = array();

    while ($arrays) {
        $array = array_shift($arrays);
        if (!is_array($array)) {
            trigger_error(__FUNCTION__ .' encountered a non array argument', E_USER_WARNING);
            return;
        }
        if (!$array)
            continue;
        foreach ($array as $key => $value)
            if (is_string($key))
                if (is_array($value) && array_key_exists($key, $merged) && is_array($merged[$key]))
                    $merged[$key] = call_user_func(__FUNCTION__, $merged[$key], $value);
                else
                    $merged[$key] = $value;
            else
                $merged[] = $value;
    }
    return $merged;
}

Which I think I stole from the PHP manual cos I didn't wanna write it myself.

I use it for combining and overwriting configuration arrays for my MVC framework, it works well.

Sammaye
  • 43,242
  • 7
  • 104
  • 146
  • This works, i'm just curious to know if there's a better solution. – daryl Jul 19 '12 at 13:45
  • @Daryl When I was looking into this in great detail that was the fastest one I found. I did make one but it's gone walkies so I just pasted this one. This function could do with optimisations but as far as I know PHP has no quick quirky way of doing this itself. – Sammaye Jul 19 '12 at 13:54