在 PHP 中合并两个数组,仅保留第一个数组的键。

6

我有这两个数组:

$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. $list中缺少的键(如'asd'键)将被简单地忽略。
  3. 即使为空,键也将保留,不会被删除。

使用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函数。


PHP提供了数组函数,它们只实现了简单的规则。而你的规则并不简单,PHP没有提供可以合并你的数组的数组函数。你必须自己编写(显然你已经做到了)。 - axiac
使用 array_walk() 函数,您可以将循环包装在一个函数中,并且它将完成所有的工作,但是不存在内置函数可以满足您想要的所有需求。 - Thielicious
4个回答

7
你可以通过以下几个步骤来实现这一目标:
$result = array_intersect_key($dataArray, $list);

这将返回一个包含第一个数组中所有元素的数组,并根据第二个数组中的键进行过滤。这样可以得到:
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);

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


问题是 'fruit' 现在只包含一个字符串,而我想将其保留为数组。 - Carlo
啊抱歉,我完全没注意到。我不确定您是否能使用内置函数来实现那个目标。我在末尾添加了一个可能的快速解决方案,希望对您有所帮助。 - iainn

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之外,没有什么方法可以使其更快或更易读。我在这里提供的代码只是另一种编写相同内容的方式。

“Spaghetti code” 意味着其他的东西,但你可以自由选择任何解决问题的答案。或者你也可以提供自己的答案。 - axiac

1

这是两行解决方案(但你可以将其简化为一行:)

$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;});

0

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

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

代码:(演示

$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 (
  ),
)

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