合并 PHP 中的 2 个数组,仅保留第一个数组中的键

Merge 2 arrays in PHP, keeping only keys from first array

我有这两个数组:

$list = [
    'fruit' => [],
    'animals' => [],
    'objects' => [],
];

$dataArray = [
    'fruit' => 'apple',
    'animals' => ['dog', 'cat'],
    'asd' => 'bla'
];

我想合并它们,使末尾的 $list 为:

[fruit] => Array
    (
        [0] => apple
    )

[animals] => Array
    (
        [0] => dog
        [1] => cat
    )

[objects] => Array
    (
    )

所以,注意事项:

  1. 即使 'fruit' 只有一个元素,在 $list
  2. 中仍然是一个数组
  3. $list 中缺少的键('asd' 键)被忽略
  4. 没有值的键仍然保留,即使是空的

使用 array_merge 无效:

$merged = array_merge($list, $dataArray);

[fruit] => apple
[animals] => Array
    (
        [0] => dog
        [1] => cat
    )

[objects] => Array
    (
    )

[asd] => bla

我设法得到了我想要的:

foreach ($dataArray as $key => $value) {
    if (isset($list[$key])) {
        if (is_array($value)) {
            $list[$key] = $value;
        }
        else {
            $list[$key] = [$value];
        }

    }

}

但我想知道是否有更简洁的方法或其他一些我不知道的 php 功能。

您可以通过几个步骤实现此目的:

$result = array_intersect_key($dataArray, $list);

这将为您 return 一个包含第一个数组中所有元素的数组,然后过滤第二个数组中的键。这给你:

Array
(
  [fruit] => apple
  [animals] => Array
    (
        [0] => dog
        [1] => cat
    )
)

然后您可以重新添加第一个数组中缺少的键,使用:

$result + $list;

+ 运算符和 array_merge 之间的区别在于前者不会使用第二个数组的值覆盖第一个数组。它只会添加任何缺失的元素。

在一行中,结果为:

$result = array_intersect_key($dataArray, $list) + $list;

您可以在此处查看实际效果:https://eval.in/865733

编辑: 抱歉,完全错过了将元素保留为数组的部分。如果它们总是数组,那么您可以添加一个快速的单行代码,例如:

$result = array_map(function ($e) { return (array) $e; }, $result);

这会将所有顶级元素转换为数组。如果您的逻辑比这更复杂,那么我不确定您是否会找到一种方法来使用内置函数,抱歉。

第二条规则(“2. $list 中缺少的键('asd' 键)被简单地忽略了”)告诉我迭代 $list,没有超过 $dataArray。如果 $dataArray$list 大得多,迭代它是浪费时间,因为它的大部分元素都被忽略了。

你的规则没有解释如何处理 $list 的元素,当它们不为空时(我假设它们总是数组,否则游戏会改变并且提供通用代码变得太复杂了处理它)。

我建议的代码如下所示:

// Build the result in $result
// (you can modify $list as well if you prefer it that way)
$result = array();

// 2. keys missing from $list ('asd' key) are simply ignored
// iterate over the keys of $list, handle only the keys present in $dataArray
foreach ($list as $key => $value) {
    if (array_key_exists($dataArray, $key)) {
        // $key is present in $dataArray, use the value from $dataArray
        $value = $dataArray[$key];

        // 1. even if 'fruit' had only one element, is still an array in $list
        if (! is_array($value)) {
            $value = array($value);
        }
    }

    // 3. keys with no values are still kept, even if empty
    // if the key is not present in $dataArray, its value from $list is used
    $result[$key] = $value;
}

如果将 if (! is_array($value)) 块移到 if (array_key_exists()) 块之外,它也会将 $list 的值转换为数组,这些值不是数组并且与不存在的键相关联在 $dataArray 中(例如 $list['objects'])。这样,代码运行后,$result的所有值都是数组。


你的代码也不错。除了遍历 $list 而不是遍历 $dataArray 之外,没有办法让它更快或更容易以惊人的方式阅读。我在这里建议的代码只是编写相同内容的另一种方式。

我的方法将执行 3 个非常简单的操作:

  1. 运行 单个循环,同时使用 &$v.
  2. 通过引用修改 $list
  3. 忽略在 $dataArray 中找不到匹配键的迭代。
  4. $dataArray 中的每个合格值强制转换为数组并覆盖初始的空子数组。 如果限定值不是数组,它将成为生成的子数组中的唯一元素;如果是,则子数组没有任何变化。

代码:(Demo)

$list = [
    'fruit' => [],
    'animals' => [],
    'objects' => []
];

$dataArray = [
    'fruit' => 'apple',
    'animals' => ['dog', 'cat'],
    'asd' => 'bla'
];

foreach ($list as $k => &$v) {
    if (isset($dataArray[$k])) {
        $v = (array)$dataArray[$k];
    }
}

var_export($list);

输出:

array (
  'fruit' => 
  array (
    0 => 'apple',
  ),
  'animals' => 
  array (
    0 => 'dog',
    1 => 'cat',
  ),
  'objects' => 
  array (
  ),
)

这是两行解决方案(但你可以简单地把它变成一行:))

$list = [
    'fruit' => [],
    'animals' => [],
    'objects' => [],
];

$dataArray = [
    'fruit' => 'apple',
    'animals' => ['dog', 'cat'],
    'asd' => 'bla'
];   

$list = array_merge($list, array_intersect_key($dataArray, $list));
array_walk($list, function(&$item){$item = (array)$item;});