Created
January 20, 2012 08:43
-
-
Save ptz0n/1646171 to your computer and use it in GitHub Desktop.
Recursive merge of arrays with integer keys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Merge two dimensional arrays my way | |
* | |
* Will merge keys even if they are of type int | |
* | |
* @param array $array1 Initial array to merge. | |
* @param array ... Variable list of arrays to recursively merge. | |
* | |
* @author Erik Pettersson <[email protected]> | |
*/ | |
function array_merge_myway() | |
{ | |
$output = array(); | |
foreach(func_get_args() as $array) { | |
foreach($array as $key => $value) { | |
$output[$key] = isset($output[$key]) ? | |
array_merge($output[$key], $value) : $value; | |
} | |
} | |
return $output; | |
} | |
/** | |
* Version of array_merge_recursive without overwriting numeric keys | |
* | |
* @param array $array1 Initial array to merge. | |
* @param array ... Variable list of arrays to recursively merge. | |
* | |
* @link http://www.php.net/manual/en/function.array-merge-recursive.php#106985 | |
* @author Martyniuk Vasyl <[email protected]> | |
*/ | |
function array_merge_recursive_new() | |
{ | |
$arrays = func_get_args(); | |
$base = array_shift($arrays); | |
foreach($arrays as $array) { | |
reset($base); | |
while(list($key, $value) = @each($array)) { | |
if(is_array($value) && @is_array($base[$key])) { | |
$base[$key] = array_merge_recursive_new($base[$key], $value); | |
} | |
else { | |
$base[$key] = $value; | |
} | |
} | |
} | |
return $base; | |
} | |
/** | |
* Marge arrays recursively and distinct | |
* | |
* Merges any number of arrays / parameters recursively, replacing | |
* entries with string keys with values from latter arrays. | |
* If the entry or the next value to be assigned is an array, then it | |
* automagically treats both arguments as an array. | |
* Numeric entries are appended, not replaced, but only if they are | |
* unique | |
* | |
* @param array $array1 Initial array to merge. | |
* @param array ... Variable list of arrays to recursively merge. | |
* | |
* @link http://www.php.net/manual/en/function.array-merge-recursive.php#96201 | |
* @author Mark Roduner <[email protected]> | |
*/ | |
function array_merge_recursive_distinct() | |
{ | |
$arrays = func_get_args(); | |
$base = array_shift($arrays); | |
if(!is_array($base)) $base = empty($base) ? array() : array($base); | |
foreach($arrays as $append) { | |
if(!is_array($append)) $append = array($append); | |
foreach($append as $key => $value) { | |
if(!array_key_exists($key, $base) and !is_numeric($key)) { | |
$base[$key] = $append[$key]; | |
continue; | |
} | |
if(is_array($value) or is_array($base[$key])) { | |
$base[$key] = array_merge_recursive_distinct($base[$key], $append[$key]); | |
} | |
else if(is_numeric($key)) | |
{ | |
if(!in_array($value, $base)) $base[] = $value; | |
} | |
else { | |
$base[$key] = $value; | |
} | |
} | |
} | |
return $base; | |
} | |
$first = array( | |
1327006800 => array('avgresponse' => 1803), | |
1327003200 => array('avgresponse' => 1453) | |
); | |
$second = array( | |
1327006800 => array('pageviews' => 123), | |
1327003200 => array('pageviews' => 345) | |
); | |
/** | |
* Test functions | |
* | |
*/ | |
echo '<pre>'; | |
// Recursive array merge will not work as expected | |
echo 'array_merge_recursive fails: '; | |
print_r(array_merge_recursive($first, $second)); | |
// Let's try our function out | |
echo "\n", 'array_merge_myway success: '; | |
print_r(array_merge_myway($first, $second)); | |
// Let's try another one | |
echo "\n", 'array_merge_recursive_new works too: '; | |
print_r(array_merge_recursive_new($first, $second)); | |
// Let's try another one | |
echo "\n", 'array_merge_recursive_distinct also works: '; | |
print_r(array_merge_recursive_distinct($first, $second)); |
Great solution. But I need help for a small change to support the follow array-merge:
{"A":{"test":[]}}
+
{"A":{"test":["test1"]}}
+
{"A":{"test":["test2"]}}
=> for this result:
{"A":
{"test":{
"0":["test1"],
"1":["test2"]
}
}
}
Can you help me? Its the same as your rekursiv merge function, but with your solution the ["test1"] will overrided by ["test2"], because he don't increment the key.
If this function is required targeting PHP v8 (the each command is deprecated) you could do it this way:
function array_merge_recursive_new() {
$arrays = func_get_args();
$base = array_shift($arrays);
foreach ($arrays as $array) {
foreach (array_keys($array) as $i => $key) {
$value = array_values($array)[$i];
$base[$key] = is_array($value) && is_array($base[$key]) ? array_merge_recursive_new($base[$key], $value) : $value;
}
}
return $base;
}
Thank you so much, I was struggling with integer keys
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much, I couldn't figure this one on my own.
However after heavy usage I definitely recommend everyone to test the array_key_exists() against the bool data type with === (or !==) operator, rather than counting on !array_key_exists() - because when the searched key index is 0, then it also evaluates to false which can cause trouble.