如何合并数组并保留键名?

93

我有两个数组:

$array1 = array('a' => 1, 'b' => 2, 'c' => 3);
$array2 = array('d' => 4, 'e' => 5, 'f' => 6, 'a' => 'new value', '123' => 456);

我想要合并它们,保留键和顺序并且不重新索引!!

如何做到这一点?

Array
(
    [a] => new value
    [b] => 2
    [c] => 3
    [d] => 4
    [e] => 5
    [f] => 6
    [123] => 456
)

我尝试使用array_merge()函数,但它不会保留键名:

print_r(array_merge($array1, $array2));

Array
(
    [a] => 'new value'
    [b] => 2
    [c] => 3
    [d] => 4
    [e] => 5
    [f] => 6
    [0] => 456
)

我尝试使用联合运算符,但它不会覆盖该元素:

print_r($array1 + $array2);

Array
(
    [a] => 1   <-- not overwriting
    [b] => 2
    [c] => 3
    [d] => 4
    [e] => 5
    [f] => 6
    [123] => 456
)

我尝试交换位置但顺序不对,不符合我的需求:

print_r($array2 + $array1);

Array
(
    [d] => 4
    [e] => 5
    [f] => 6
    [a] => new value 
    [123] => 456
    [b] => 2
    [c] => 3
)

我不想使用循环,有没有一种高性能的方法?


你不只是要翻转数组合并的顺序吗?array_merge($array2, $array1); - Seth McClaine
2
array_merge() 函数的问题在于,它将 "123" 键视为数字,并对其进行重新索引。 - jcsanyi
5个回答

208

您正在寻找array_replace()函数:

$array1 = array('a' => 1, 'b' => 2, 'c' => 3);
$array2 = array('d' => 4, 'e' => 5, 'f' => 6, 'a' => 'new value', '123' => 456);
print_r(array_replace($array1, $array2));

自PHP 5.3版本起可用。

更新

您也可以使用联合数组运算符,它适用于旧版本,并且实际上可能更快:

print_r($array2 + $array1);

1
@joe 不客气。当然,仍然有一个循环,区别在于它发生的地方 :) - Ja͢ck
我的解决方案将作为一个 5.3 版本之前的函数猴子补丁。 - Orangepill
请注意,$array2 + $array1将保留第一个数组的值而不是第二个数组的值,这与人们的期望不同。 - Javier S
@JavierS 是的,这就是为什么我在那个例子中颠倒了顺序与第一个相比 :) - Ja͢ck

6
假设我们有以下三个数组。
$a = array(0=>['label'=>'Monday','is_open'=>1],1=>['label'=>'Tuesday','is_open'=>0]);

$b = array(0=>['open_time'=>'10:00'],1=>['open_time'=>'12:00']); 

$c = array(0=>['close_time'=>'18:00'],1=>['close_time'=>'22:00']); 

现在,如果您想合并所有这些数组,并希望最终的数组将所有数组的数据放在键0下,在键1下放置1等等。

那么您需要使用 array_replace_recursive PHP函数,如下所示。

$final_arr = array_replace_recursive($a, $b , $c); 

这将产生以下结果。
Array
(
    [0] => Array
        (
            [label] => Monday
            [is_open] => 1
            [open_time] => 10:00
            [close_time] => 18:00
        )

    [1] => Array
        (
            [label] => Tuesday
            [is_open] => 0
            [open_time] => 12:00
            [close_time] => 22:00
        )

)

希望上述解决方案能够最适合您的需求!

4

@Jack发现了一个本地函数可以做到这一点,但由于它仅在php 5.3及以上版本中可用,因此在先前的5.3安装中应该使用此方法来模拟此功能。

  if(!function_exists("array_replace")){
      function array_replace(){
         $args = func_get_args();
         $ret = array_shift($args);
         foreach($args as $arg){
             foreach($arg as $k=>$v){
                $ret[(string)$k] = $v;
             }
         }
         return $ret;
     }
 }

我不想使用循环,有没有高性能的方法? - Jasper
我想不出一个能满足数字键要求的解决方案。但是不要排除这个解决方案,我认为循环不会导致你想象中的性能问题。 - Orangepill
你可以通过将$ret直接设置为第一个数组,然后在其上合并其他数组来进行优化。 - jcsanyi
@jcsanyi 好主意...我修改了我的答案,包括了你的优化,并更改措辞,将Jack的解决方案称为本地方式,而将我的解决方案称为5.3之前版本的备选方案。 - Orangepill

3

array_replace_recursive() 或者 array_replace() 是你需要的函数。

$array1 = array('a' => 1, 'b' => 2, 'c' => 3);
$array2 = array('d' => 4, 'e' => 5, 'f' => 6, 'a' => 'new value', '123' => 456);


var_dump(array_replace_recursive($array1, $array2));

演示


-2

如果我理解正确,我认为这可能会有所帮助:

foreach ($i = 0, $num = count($array2); $i < $num; $i++)
{
  $array = array_merge($array1, $arrar2[$i]);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接