数组合并:array_merge与+的区别

134

当我使用 array_merge() 合并关联数组时,得到了我想要的结果,但当我使用它来合并数字键数组时,键被改变了。

使用 + 可以保留键,但它不适用于关联数组。

我不理解它是如何运作的,有人可以为我解释一下吗?

2个回答

180

因为两个数组都是按数字索引的,所以只使用第一个数组中的值。

+ 运算符返回右侧数组附加到左侧数组; 对于在两个数组中都存在的键,将使用左侧数组的元素,并忽略右侧数组中匹配的元素。

http://php.net/manual/en/language.operators.array.php

array_merge() 的行为略有不同:

如果输入数组具有相同的字符串键,则该键的后一个值将覆盖前一个值。 但是,如果数组包含数字键,则后一个值不会覆盖原始值,而是被附加在后面。 输入数组中具有数字键的值将在结果数组中以从零开始的递增键重新编号。

http://php.net/manual/en/function.array-merge.php


1
array_merge是我想要的,但为什么它会改变数字索引呢?如果我将array(1 => 'a', 2 => 'b')array(20 => 'x')合并,我得到的是0、1、2索引,而不是1、2、20 :| - Elly
5
嗯... 所以+就像是带有反向参数的array_merge,并且没有数值键重新编号?这意味着我只需要颠倒我的参数。 - Elly
我正在处理的一些代码中,之前的开发人员在每个场合都使用+来合并数组。如果你不确切知道它的作用,这会给其他人带来很多问题和过早的脱发。非常好的回答! - Matt Fletcher
@MattFletcher,实际上没有看到你的代码,很难说他为什么那样做。也许他的一个目的是避免重新编号? - Denis V
6
在我们的代码库中,我们停止使用加号和array_merge函数来处理数组,而是使用了我们编写的两个新函数:"array_merge_by_key" 和 "array_concat"。这样做可以避免使用启发式算法猜测你的意图,而采用更加明确的方式。 - Yuliy
显示剩余2条评论

40

这两个操作完全不同。

数组相加

  1. 数组相加操作将所有数组视为关联数组。
  2. 当键名冲突时,左侧(先前)的值将被保留。
  3. null + array()会引发致命错误。

array_merge()

  1. array_merge()对索引数组和关联数组的处理不同。
  2. 如果两个参数都是索引数组,array_merge()将连接索引数组的值。
  3. 如果不是,则将索引数组转换为值数组,然后将其转换为关联数组。
  4. 现在有两个关联数组,将它们合并在一起,当键名冲突时,右侧(最后)的值将被保留。
  5. array_merge(null, array()) 返回array()并出现警告,警告信息为第一个参数不是数组。

为了更加清晰明了,我在下面附上了代码。

function array_plus($a, $b){
    $results = array();
    foreach($a as $k=>$v) if(!isset($results[$k]))$results[$k] = $v;
    foreach($b as $k=>$v) if(!isset($results[$k]))$results[$k] = $v;
    return $results;
}

//----------------------------------------------------------------

function is_index($a){
    $keys = array_keys($a);
    foreach($keys as $key) {
        $i = intval($key);
        if("$key"!="$i") return false;
    }
    return true;
}

function array_merge($a, $b){
    if(is_index($a)) $a = array_values($a);
    if(is_index($b)) $b = array_values($b);
    $results = array();
    if(is_index($a) and is_index($b)){
        foreach($a as $v) $results[] = $v;
        foreach($b as $v) $results[] = $v;
    }
    else{
        foreach($a as $k=>$v) $results[$k] = $v;
        foreach($b as $k=>$v) $results[$k] = $v;
    }
    return $results;
}

2
示例代码很棒,但是很难阅读。如果格式正确的话会好得多... - Yep_It's_Me
事实上,您的实现很棒,除了它无法像内置的 array_merge 函数一样给出相同的结果。如果您想看到差异,请比较运行 var_dump(array_merge(['a'=>1, 'b'=>2, 3, 4], ['a'=>5, 'b'=>6, 7, 8]));var_dump(your_array_merge(['a' => 1, 'b' => 2, 3, 4], ['a' => 5, 'b' => 6, 7, 8])); 的结果(我已将您的实现重命名为 your_array_merge 避免函数重新定义)。区别在于原始实现在处理混合数组的数字和字符串键时有所不同。 - Aleksander Z.

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