百科狗-知识改变命运!
--

array_merge_recursive() - 递归地合并一个或多个数组 - php 数组函数

百变鹏仔1年前 (2023-11-21)阅读数 14#技术干货
文章标签数组

array_merge_recursive()

(PHP 4 >= 4.0.1, PHP 5, PHP 7)

递归地合并一个或多个数组

说明

array_merge_recursive(array $array1[,array $...]): array

array_merge_recursive()将一个或多个数组的单元合并起来,一个数组中的值附加在前一个数组的后面。返回作为结果的数组。

如果输入的数组中有相同的字符串键名,则这些值会被合并到一个数组中去,这将递归下去,因此如果一个值本身是一个数组,本函数将按照相应的条目把它合并为另一个数组。需要注意的是,如果数组具有相同的数值键名,后一个值将不会覆盖原来的值,而是附加到后面。

参数

$array1

array_merge_recursive() - 递归地合并一个或多个数组 - php 数组函数

要合并的初始数组。

数组变量列表,进行递归合并。

返回值

一个结果数组,其中的值合并自附加的参数。

范例

Example #1array_merge_recursive()例子

以上例程会输出:

Array
(
    [color] => Array
        (
            [favorite] => Array
                (
                    [0] => red
                    [1] => green
                )
            [0] => blue
        )
    [0] => 5
    [1] => 10
)

参见

  • array_merge() 合并一个或多个数组
  • array_replace_recursive() 使用传递的数组递归替换第一个数组的元素
I refactored the Daniel's function and I got it:

This fix the E_NOTICE when the the first array doesn't have the key and the second array have a value which is a array.
If what you want is merge all values of your array that are arrays themselves to get a resulting array of depth one, then you're more looking for array_flatten function.
Unfortunately I did not find such native function in php, here is the one I wrote: 
I little bit improved daniel's and gabriel's contribution to behave more like original array_merge function to append numeric keys instead of overwriting them and added usefull option of specifying which elements to merge as you more often than not need to merge only specific part of array tree, and some parts of array just need to let overwrite previous. By specifying helper element mergeWithParent=true, that section of array will be merged, otherwise latter array part will override former. First level of array behave as classic array_merge.
    function array_merge_recursive_distinct ( array &$array1, array &$array2 )
  {
    static $level=0;
    $merged = [];
    if (!empty($array2["mergeWithParent"]) || $level == 0) {
      $merged = $array1;
    }
    foreach ( $array2 as $key => &$value )
    {
      if (is_numeric($key)) {
        $merged [] = $value;
      } else {
        $merged[$key] = $value;
      }
      if ( is_array ( $value ) && isset ( $array1 [$key] ) && is_array ( $array1 [$key] )
      ) {
        $level++;
        $merged [$key] = array_merge_recursive_distinct($array1 [$key], $value);
        $level--;
      }
    }
    unset($merged["mergeWithParent"]);
    return $merged;
  }
There are a lot of examples here for recursion that are meant to behave more like array_merge() but they don't get it quite right or are fairly customised. I think this version is most similar, takes more than 2 arguments and can be renamed in one place:

gives:
array(7) {       array(7) {       array(7) {
 int(1)         int(1)         int(1)
 ["foo"]=>        ["foo"]=>        ["foo"]=>
 array(1) {       array(1) {       array(2) {
  [0]=>          [0]=>          [0]=>
  int(8)         int(8)         int(2)
 }            }             [1]=>
 ["bar"]=>        ["bar"]=>         int(8)
 int(9)         int(9)         }
 ["x"]=>         ["x"]=>         ["bar"]=>
 int(5)         int(5)         array(2) {
 ["z"]=>         ["z"]=>          [0]=>
 array(1) {       array(3) {        int(4)
  ["m"]=>         [0]=>          [1]=>
  string(4) "ciao"    int(6)         int(9)
 }             ["m"]=>        }
 [1]=>           string(4) "ciao"   ["x"]=>
 int(7)          [1]=>         int(5)
 ["y"]=>          int(11)        ["z"]=>
 int(10)         }            array(3) {
}             [1]=>           [0]=>
             int(7)          int(6)
             ["y"]=>          ["m"]=>
             int(10)          array(3) {
            }               [0]=>
                           string(2) "hi"
                           [1]=>
                           string(3) "bye"
                           [2]=>
                           string(4) "ciao"
                          }
                          [1]=>
                          int(11)
                         }
                         [1]=>
                         int(7)
                         ["y"]=>
                         int(10)
                        }
This is my version of array_merge_recursive without overwriting numeric keys: 
This is a simple, three line approach.
Short description: If one of the Arguments isn't an Array, first Argument is returned. If an Element is an Array in both Arrays, Arrays are merged recursively, otherwise the element in $ins will overwrite the element in $arr (regardless if key is numeric or not). This also applys to Arrays in $arr, if the Element is scalar in $ins (in difference to the previous approach).
 function array_insert($arr,$ins) {
  # Loop through all Elements in $ins:
  if (is_array($arr) && is_array($ins)) foreach ($ins as $k => $v) {
   # Key exists in $arr and both Elemente are Arrays: Merge recursively.
   if (isset($arr[$k]) && is_array($v) && is_array($arr[$k])) $arr[$k] = array_insert($arr[$k],$v);
   # Place more Conditions here (see below)
   # ...
   # Otherwise replace Element in $arr with Element in $ins:
   else $arr[$k] = $v;
  }
  # Return merged Arrays:
  return($arr);
 }
In Addition to felix dot ospald at gmx dot de in my opinion there is no need to compare keys with type-casting, as a key always is changed into an integer if it could be an integer. Just try
$a = array('1'=>'1');
echo gettype(key($a));
It will echo 'integer'. So for having Integer-Keys simply appended instead of replaced, add the Line:
 elseif (is_int($k)) $arr[] = $v;
A Condition I used is:
 elseif (is_null($v)) unset($arr[$k]);
So a NULL-Value in $ins will unset the correspondig Element in $arr (which is different to setting it to NULL!). This may be another Addition to felix dot ospald at gmx dot de: The absolute correct way to check for a Key existing in an Array is using array_key_exists() (not needed in the current context, as isset() is combined with is_array()). array_key_exists() will return TRUE even if the Value of the Element is NULL.
And the last one: If you want to use this approach for more than 2 Arrays, simply use this:
 function array_insert_mult($arr) {
  # More than 1 Argument: Append all Arguments.
  if (func_num_args() > 1) foreach (array_slice(func_get_args(),1) as $ins) $arr = array_insert($arr,$ins);
  # Return merged Arrays:
  return($arr);
 }
And if you worry about maintaining References: Simply use $ins[$k] instead of $v when assigning a Value/using a Value as Argument.
This function didn't work for me - or it didn't do what I thought it would. So I wrote the below function, which merges two arrays, and returns the resulting array. The base array is the left one ($a1), and if a key is set in both arrays, the right value has precedence. If a value in the left one is an array and also an array in the right one, the function calls itself (recursion). If the left one is an array and the right one exists but is not an array, then the right non-array-value will be used.
*Any key only appearing in the right one will be ignored* 
 - as I didn't need values appearing only in the right in my implementation, but if you want that you could make some fast fix.
function array_merge_recursive_leftsource(&$a1, &$a2) {
  $newArray = array();
  foreach ($a1 as $key => $v) {
    if (!isset($a2[$key])) {
      $newArray[$key] = $v;
      continue;
    }
    if (is_array($v)) {
      if (!is_array($a2[$key])) {
        $newArray[$key] = $a2[$key];
        continue;
      }
      $newArray[$key] = array_merge_recursive_leftsource($a1[$key], $a2[$key]);
      continue;
    }
    $newArray[$key] = $a2[$key];
  }
  return $newArray;
}
Here's my function to recursively merge two arrays with overwrites. Nice for merging configurations. 
Here is a fairly simple function that replaces while recursing.

Examples:

Result 1 is:
Array
(
  [liquids] => Array
    (
      [water] => hot
      [beer] => warm
      [milk] => wet
    )
)
Result 2 is:
Array
(
  [liquids] => Array
    (
      [water] => Array
        (
          [0] => cold
          [1] => fizzy
          [2] => clean
        )
      [milk] => wet
      [beer] => warm
    )
)
The presence of NULLs; here is an example of the issue and a fix. Although it may not be apparent, if using array_merge_recursive in a loop to combine results from a database query or some other function, you can corrupt your result when NULLs are present in the data. I discovered this when migrating from an Oracle DB to a MySQL DB. I had to match the array structure returned from the PHP function calling the DB and got bit. The array_walk call fixed this for me.
This is a simple example that lacks any DB calls and looping. Assume your array had the DB column names (first, last, and age) and you needed to combine the data in a multi-dimensional array in which the column name is an array key with all rows beneath it. The corruption occurs in $a3. If using element position 2, one could create the fictitious 'pete johnson' because of the collapsing of elements. 
I've edit this version even a little bit more, so that the function does not override any values, but inserts them at a free key in the array:
function my_array_merge ($arr,$ins) {
  if(is_array($arr))
  {
    if(is_array($ins)) foreach($ins as $k=>$v)
    {
      if(isset($arr[$k])&&is_array($v)&&is_array($arr[$k]))
      {
        $arr[$k] = my_array_merge($arr[$k],$v);
      }
      else {
        // This is the new loop :)
        while (isset($arr[$k]))
          $k++;
        $arr[$k] = $v;
      }
    }
  }
  elseif(!is_array($arr)&&(strlen($arr)==0||$arr==0))
  {
    $arr=$ins;
  }
  return($arr);
}
Example:
$array1 = array(
  100 => array(30),
  200 => array(20, 30)
);
$array2 = array(
  100 => array(40),
  201 => array(60, 30)
);
print_r(my_array_merge($array1,$array2));
Output with array_merge_recursive:
Array
(
  [0] => Array
    (
      [0] => 30
    )
  [1] => Array
    (
      [0] => 20
      [1] => 30
    )
  [2] => Array
    (
      [0] => 40
    )
)
This is not the result, I expect from a MERGE-Routine...
Output with the current function:
Array
(
  [100] => Array
    (
      [0] => 30
      [1] => 40
    )
  [200] => Array
    (
      [0] => 20
      [1] => 30
    )
)
This is what I want :)
In this version the values are overwritten only if they are not an array. If the value is an array, its elements will be merged/overwritten:
// array_merge_recursive which override value with next value.
// based on: http://www.php.net/manual/hu/function.array-merge-recursive.php 09-Dec-2006 03:38
function array_merge_recursive_unique($array0, $array1)
{
  $arrays = func_get_args();
  $remains = $arrays;
  // We walk through each arrays and put value in the results (without
  // considering previous value).
  $result = array();
  // loop available array
  foreach($arrays as $array) {
    // The first remaining array is $array. We are processing it. So
    // we remove it from remaing arrays.
    array_shift($remains);
    // We don't care non array param, like array_merge since PHP 5.0.
    if(is_array($array)) {
      // Loop values
      foreach($array as $key => $value) {
        if(is_array($value)) {
          // we gather all remaining arrays that have such key available
          $args = array();
          foreach($remains as $remain) {
            if(array_key_exists($key, $remain)) {
              array_push($args, $remain[$key]);
            }
          }
          if(count($args) > 2) {
            // put the recursion
            $result[$key] = call_user_func_array(__FUNCTION__, $args);
          } else {
            foreach($value as $vkey => $vval) {
              $result[$key][$vkey] = $vval;
            }
          }
        } else {
          // simply put the value
          $result[$key] = $value;
        }
      }
    }
  }
  return $result;
}
Sharing my code to reserve the numeric keys:
  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);
  }
walfs version is pretty good, but it always assumes we want numeric keys as numeric keys. There are possibilities where a numeric key is actually a string '123'
For that I modified the function so that the last argument is a true switch to turn keys can be numeric on. Default is that keys are all string. 
I would merge 2 arrays but keep the values unique in the result array.
I hope this will help... 
If you desire correct and performant behaviour (in contrast to the other postings) use this code. It works as documented above.
If you want that keys are always perserved and not appended or renumbered if they are numeric comment out the "if (((string) $key) === ((string) intval($key)))" case.
@spambegone at cratemedia dot com: using empty is not right way to check if an item is in the array use isset! 
I wrote the following for merging arrays, in my project mainly for configuration... Thought someone else might find it usefull.
function array_merge_recursive_keys( $first, $second, $greedy=false) {
  $inter = array_intersect_assoc(array_keys($first), array_keys($second)); # shaired keys
# the idea next, is to strip and append from $second into $first
  foreach ( $inter as $key ) {
  # recursion if both are arrays
   if ( is_array($first[$key]) && is_array($second[$key]) ) {
     $first[$key] = array_merge_recursive_keys($first[$key], $second[$key]);
   }
  # non-greedy array merging:
   else if ( is_array($first[$key] && !$greedy ) ) {
     $first[$key][] = $second[$key];
   }
   else if ( is_array($second[$key]) && !$greedy ) {
     $second[$key][] = $first[$key];
     $first[$key] = $second[$key];
   }
  # overwrite...
   else {
     $first[$key] = $second[$key];
   }
   unset($second[$key]);
  }
# merge the unmatching keys onto first
  return array_merge($first, $second);
}
This emulates replace of $_REQUEST according to variable_order=GPC.

Useful with stripping backslashes at beginning of main include file:

Based on examples from users from this site.
Please be aware that under circumstances where you have 
both the key and value common between the two arrays at a given node,
array_merge_recursive() will behave differently if that value is NULL,
as opposed to a non-null value.
i.e., I expected the results of the first two sections below to 
have the same structure, but they don't. 
If this might apply to you, please see for yourself.
This behavior also occurs if the value is the empty array.
In fact, in the above example, interchanging the empty array with
any and all occurences of NULL will yield the same result.
  code till dawn! -mark
This function tends to reindex arrays, which is not mentioned in the function description.
I just tried to run that function on a three dimensional array, containing errormessages.
The first dim. contains the severity of the error ('warn', 'crit') the second dim the linenumber (numerical) and the third one consists of errormessages

If i now merge two or more of those arrays using array_merge_recursive(), the linenumbers are not conserved. Instead of, they are all renumbered, starting with 0.
Just thought anyone may want to know about that. :)
regards, smilingrasta
I ran into a fairly unique situation where array_merge_recursive ALMOST did what I wanted, but NOT QUITE. I read through all of the comments, and I didn't find anything that really helped me. I saw a lot of functions submitted that were just trying to recreate array_replace_recursive. This is not that.
Take a look at the code and try it out. Hopefully it helps someone in need!
class Arr
{
  /**
   * Merge multiple arrays.
   *
   * This is similar to, but slightly different than array_merge_recursive.
   * The main difference is that it will merge like keys in subarrays,
   * instead of simply pushing them into the output array.
   *
   * @param array ...$array
   *
   * @return array
   */
  public static function merge()
  {
    /** Initialize the output array */
    $merged = [];
    /** Go through each argument */
    foreach (func_get_args() as $array) {
      /** Go through each key/value of this array */
      foreach ($array as $key => $value) {
        /**
         * If this key isn't set on merged,
         * then it needs to be set for the first time
         */
        if (! isset($merged[$key])) {
          /**
           * Before we can set it, we must make sure
           * to dive into this value if it is an array,
           * so that all of its children will be processed.
           */
          if (is_array($value)) {
            $value = static::merge($value);
          }
          /**
           * Now that we're happy with this value,
           * and we're sure that, if it is an array,
           * all of its children have been processed,
           * let's go ahead and set it.
           */
          $merged[$key] = $value;
          /** We can skip the rest of the loop */
          continue;
        }
        /**
         * We're here because we want to set a key
         * that is already set on merged. We don't want
         * to overwrite anything - we want to add to it.
         * So, we need to make sure that we're working with an array.
         */
        if (! is_array($merged[$key])) {
          $merged[$key] = [$merged[$key]];
        }
        /**
         * Before we push the value onto the array,
         * we need to check to see if it is an array itself.
         * If it is, then we need to make sure all of its children
         * are processed. We do this by merging all of the children
         * together. This is where it differs from array_merge_recursive,
         * which would simply push the children onto the end of the array.
         */
        if (is_array($value)) {
          $value = forward_static_call_array([Arr::class, 'merge'], $value);
        }
        /** Now we're ready to push the value into merged */
        $merged[$key][] = $value;
      }
    }
    /** Return the merged array */
    return $merged;
  }
}
Needed some way to fuse two arrays together and found a function here (below from thomas) and decided to update it even further to be a little more smart. 
An updated version of array_merge_recursive without overwriting numeric keys from martyniuk : 
function array_merge_recursive_new()
 {
  $arrays = func_get_args();
    $base = array_shift($arrays);
    foreach ($arrays as $array) {
      reset($base); //important
      while (list($key, $value) = @each($array)) {
        if (is_array($value) && @is_array($base[$key])) {
          $base[$key] = array_merge_recursive_new($base[$key], $value);
        } else {
          if(isset($base[$key]) && is_int($key)) {
           $key++;
          }
          $base[$key] = $value;
        }
      }
    }
  return $base;
 }

鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com

免责声明:我们致力于保护作者版权,注重分享,当前被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!邮箱:344225443@qq.com)

图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

内容声明:本文中引用的各种信息及资料(包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主体(包括但不限于公司、媒体、协会等机构)的官方网站或公开发表的信息。部分内容参考包括:(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供参考使用,不准确地方联系删除处理!本站为非盈利性质站点,本着为中国教育事业出一份力,发布内容不收取任何费用也不接任何广告!)