php - 为什么 array_merge_recursive 不是递归的?
问题描述
我最近在我的应用程序中发现了一个由array_merge_recursive
. 让我们看一下这个简单的例子:
$array1 = [
1 => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
3 => [
1 => 500
]
];
$array2 = [
3 => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:4 [ 0 => //...
我希望得到一个包含 3 个元素的数组:键 1、2 和 3。但是,该函数返回一个包含键 0、1、2 和 3 的数组。所以 4 个元素,而我期望只有 3 个。当我替换数字时通过它们的字母等价物(a,b,c),它返回一个只有 3 个元素的数组:a,b 和 c。
$array1 = [
'a' => [
1 => 100,
2 => 200,
],
'b' => [
3 => 1000,
],
'c' => [
1 => 500
]
];
$array2 = [
'c' => [
1 => 500
]
];
array_merge_recursive($array1, $array2);
//returns: array:3 [ 'a' => //...
这是(至少对我而言)意想不到的行为,但至少它被记录在案:
http://php.net/manual/en/function.array-merge-recursive.php
如果输入数组具有相同的字符串 keys,则这些键的值将合并到一个数组中,这是递归完成的,因此如果其中一个值是数组本身,则该函数会将其与相应的条目合并在另一个数组中。但是,如果数组具有相同的数字键,则后面的值不会覆盖原始值,而是会被追加。
该文档对“附加”的含义不是很清楚。事实证明,$array1
带有数字键的元素将被视为索引元素,因此它们将丢失当前键:返回的数组以 0 开头。当在数组中同时使用数字键和字符串键时,这将导致奇怪的结果,但是,如果您使用这样的不良做法,我们不要责怪 PHP。就我而言,问题是通过使用array_replace_recursive
来解决的,这达到了预期的效果。(该函数中的“替换”表示如果存在则替换,否则附加;命名函数很难!)
问题1:递归与否?
但这不是这个问题的结束。我认为array_*_resursive
这将是一个递归函数:
递归是一种函数调用,其中函数调用自身。此类函数也称为递归函数。结构递归是一种解决问题的方法,其中问题的解决方案取决于同一问题的较小实例的解决方案。
事实证明不是。虽然$array1
和$array2
是关联数组,但上例中的$array1['c']
和$array2['c']
都是具有一个元素的索引数组:[1 => 500]
. 让我们合并它们:
array_merge_recursive($array1['c'], $array2['c']);
//output: array:2 [0 => 500, 1 => 500]
这是预期的输出,因为两个数组都有一个数字键 ( 1
),所以第二个将附加到第一个。新数组以键 0 开头。但让我们回到第一个示例:
array_merge_recursive($array1, $array2);
// output:
// array:3 [
// "a" => array:2 [
// 1 => 100
// 2 => 200
// ]
// "b" => array:1 [
// 3 => 1000
// ]
// "c" => array:2 [
// 1 => 500 //<-- why not 0 => 500?
// 2 => 500
// ]
//]
$array2['c'][1]
附加到$array1['c']
但它有键 1 和 2。不是前面示例中的 0 和 1。在处理整数键时,主数组及其子数组的处理方式不同。
问题 2:字符串或整数键有很大的不同。
在写这个问题的时候,我发现了一些别的东西。用子数组中的字符串键替换数字键时会变得更加混乱:
$array1 = [
'c' => [
'a' => 500
]
];
$array2 = [
'c' => [
'a' => 500
]
];
array_merge_recursive($array1, $array2);
// output:
// array:1 [
// "c" => array:1 [
// "a" => array:2 [
// 0 => 500
// 1 => 500
// ]
// ]
//]
因此,使用字符串键将(int) 500
转换为array(500)
,而使用整数键则不会。
有人可以解释这种行为吗?
解决方案
如果我们退后一步,观察array_merge*()
函数只对一个数组的行为,那么我们就会看到它如何以不同的方式处理关联数组和索引数组:
$array1 = [
'k' => [
1 => 100,
2 => 200,
],
2 => [
3 => 1000,
],
'f' => 'gf',
3 => [
1 => 500
],
'99' => 'hi',
5 => 'g'
];
var_dump( array_merge_recursive( $array1 ) );
输出:
array(6) {
["k"]=>
array(2) {
[1]=>
int(100)
[2]=>
int(200)
}
[0]=>
array(1) {
[3]=>
int(1000)
}
["f"]=>
string(2) "gf"
[1]=>
array(1) {
[1]=>
int(500)
}
[2]=>
string(2) "hi"
[3]=>
string(1) "g"
}
如您所见,它获取了所有数字键并忽略了它们的实际值,并按照遇到它们的顺序将它们返回给您。我想该函数这样做是为了在底层 C 代码中保持理智(或效率)。
回到您的两个数组示例,它获取 的值,对$array1
它们进行排序,然后附加$array2
。
这种行为是否理智是一个完全独立的讨论......
推荐阅读
- javascript - 在哪里使用 `var` 和 `let` 在 javascript 中?(不问区别)
- javascript - 无法使用 JavaScript 在 Div 中插入 Child
- jquery - 属性“数据限制”不是 vs2013 中 aspx 页面中元素“选项”的有效属性
- php - YouTube API 循环问题
- c# - 由于 xml 声明,WCF 服务无法接收肥皂请求
- ios - Is realtime audio processing possible in iOS?
- node.js - 未找到 Heroku
- django - 获取两个日期之间的记录
- javascript - ES6 生成器笛卡尔
- java - Generic date parsing in java