php,array_merge_recursive只适用于字符串键

时间:2016-11-21 16:50:06

标签: php

$array1 = [
    '1' => '11',
    'b' => 1,
    3   => 33,
    8   => 8
];
$array2 = [
    '1' => '22',
    'b' => 2,
    3   => 44,
    9   => 9
];

$merged = array_merge_recursive($array1, $array2);

结果是:

array(7) {
  [0]=>
  string(2) "11"
  ["b"]=>
  array(2) {
    [0]=>
    int(1)
    [1]=>
    int(2)
  }
  [1]=>
  int(33)
  [2]=>
  int(8)
  [3]=>
  string(2) "22"
  [4]=>
  int(44)
  [5]=>
  int(9)
}

所以让我们一目了然:唯一的部分是'b'键,它们实际上是有效的。我不想覆盖它的任何东西,但把它们放在一个数组中。非常好!但随后键其他数字键(int或string)被搞砸了。 我希望得到这个结果:

[
  '1' => ['11', '22']
  'b' => [1, 2]
  [3] => [33, 44]
  [8] => 8,
  [9] => 9
]

可能?

编辑:当然键“1”和1 - 字符串与int键是相同的

2 个答案:

答案 0 :(得分:2)

让我们将这个问题分解为单独的问题:

  1. 当第二个数组中的键存在于第一个数组中时,您要创建一个数组并将该值设为该数组的第一个元素。

说实话,我不知道解决此问题的简便方法。我不确定是否有一个。即使,我不确定您是否真的想要它。这样的函数将导致数组的值是字符串。您将如何处理这样的数组?

更新:嗯,有一个。您的示例已经显示array_merge_recursive会将带有字符串键的值转换为数组。因此1 => 'foo'将是0 => 'foo',但是'foo' => 'bar'最终将变成'foo' => ['bar']。我真的不明白这种行为。

在这种情况下,使用字符串键可以为您提供帮助,但是在进一步了解array_merge_recursive之后,我决定尽可能避免使用此功能。在我询问this question之后,有人将其归档为bug in it since PHP 7.0,因为它在PHP 5.x中的工作方式有所不同。

  1. 您要保留键,而array_merge_resursive则不保留整数键,而保留整数键:
  

如果输入数组具有相同的 string 键,则用于   这些键被合并在一起成为一个数组,这完成了   递归,因此,如果值之一是数组本身,则   函数将其与另一个数组中的对应条目合并   太。但是,如果数组具有相同的数字键,则后者   值不会覆盖原始值,但会附加

更糟糕的是,在处理嵌套数组时,其处理方式有所不同:

    $array1 = [30 => [500 => 'foo', 600 => 'bar']];
    $array2 = [];
    array_merge_recursive($array1, $array2);
    //[0 => [500=> 'foo', 600 => 'bar']];

实际上,array_merge_resursive并不是 resursive

使用array_replace_resursive解决了这个问题:

array_replace_recursive($array1, $array2);
//output: 
//array:5 [
//  1 => "22"
//  "b" => 2
//  3 => 44
//  8 => 8
//  9 => 9
//]

请注意,PHP在不一致方面非常一致。虽然array_merge_recursive不是递归的,但是array_replace_recursive不会替代(它也会追加):

  

如果键存在于第二个数组而不是第一个数组中,它将是   在第一个数组中创建。

在许多情况下,这是期望的行为,并且由于命名功能不是PHP的强项,因此您可以将其视为次要问题。

答案 1 :(得分:1)

您能否依靠本机函数来返回您想要的确切输出?不会。至少在本文发布之日的任何版本中都没有(PHP8.1 之前)。

好消息是制定您自己的解决方案非常简单。

代码:(Demo)

foreach ($array2 as $key => $value) {
    if (!key_exists($key, $array1)) {
        $array1[$key] = $value;
    } else {
        $array1[$key] = (array)$array1[$key];
        $array1[$key][] = $value;
    }
}
var_export($array1);

我想我不太倾向于推荐这种输出结构,因为在给定级别上您可能有不同的数据类型。如果您正在构建后续代码来迭代此数据,则需要在每个级别上编写条件以查看数据是否可迭代 - 感觉就像您正在为代码膨胀/卷积做准备。我更喜欢具有一致深度和数据类型的结果。