获取两个二维数组中关联行之间的差异

7

我有两个数组,这些数组包含关于idlinklabelurl的信息,格式如下:

$pageids = [
    ['id' => 1, 'linklabel' => 'Home', 'url' => 'home'],
    ['id' => 2, 'linklabel' => 'Graphic Design', 'url' => 'graphicdesign'],
    ['id' => 3, 'linklabel' => 'Other Design', 'url' => 'otherdesign'],
    ['id' => 6, 'linklabel' => 'Logo Design', 'url' => 'logodesign'],
    ['id' => 15, 'linklabel' => 'Content Writing', 'url' => 'contentwriting'],
];

$parentpage = [
    ['id' => 2, 'linklabel' => 'Graphic Design', 'url' => 'graphicdesign'],
    ['id' => 3, 'linklabel' => 'Other Design', 'url' => 'otherdesign'],
];

我现在正尝试比较这两个变量,以查找在$pageids中存在但在$parentpage中不存在的信息 - 这将组成另一个名为$pageWithNoChildren的数组。然而,当我使用以下代码时:

$pageWithNoChildren = array_diff_assoc($pageids,$parentpage);
array_diff_assoc()在第一层级上运行,因此它看到$pageids$parentpages都具有[0]和[1]键,因此忽略它们并从$pageids中的[2]开始返回所有信息。但是我希望它查看嵌套数组的内容并比较它们,例如,我需要它查看哪些idlinklabelurl$pageids中而不在$parentpages中,并返回这些值。
如何使array_diff_assoc()在嵌套数组的键上运行而不是在第一个数组的键上,以便最终结果是一个包含来自$pageids的[0]、[3]和[4]数组内容的数组?
期望结果:
array (
  0 => 
  array (
    'id' => 1,
    'linklabel' => 'Home',
    'url' => 'home',
  ),
  3 => 
  array (
    'id' => 6,
    'linklabel' => 'Logo Design',
    'url' => 'logodesign',
  ),
  4 => 
  array (
    'id' => 15,
    'linklabel' => 'Content Writing',
    'url' => 'contentwriting',
  ),
)
5个回答

22

要检查多维度,请尝试类似以下的内容:

$pageWithNoChildren = array_map('unserialize',
    array_diff(array_map('serialize', $pageids), array_map('serialize', $parentpage)));
  • array_map()将主数组中的每个子数组通过serialize()运行,将每个子数组转换为该子数组的字符串表示
    • 现在,主数组具有的值不是数组,而是子数组的字符串表示形式
  • array_diff()现在对比的是每个数组的一维数组
  • 返回差异后,array_map()通过unserialize()运行数组结果(差异),将字符串表示转换回子数组

Q.E.D.


太棒了!谢谢!顺便问一下,你能否简单解释一下这个吗?我以前没有使用过unserialize或array_maps,现在正在查找它们,但如果您能快速介绍一下,那就太棒了。无论如何,再次感谢! - Smokescreen
我认为我可能已经找到了答案,因此对于其他阅读此内容和好奇的人们,我相信serialize()将php键和值转换为字符串,因此您在$pageids的所有数组中都有一个字符串,并且在$parentpages的所有数组中都有一个字符串。然后,array_diff函数可以比较这些字符串并挑选出在$pageids中而不在$parentpages中的那些结果,然后使用unserialize()将结果转换回php值。正是我所需要的!再次感谢! :) - Smokescreen
谢谢!我刚刚阅读了你的逐步说明,并找到了一些文档,你所说的基本上就是我从阅读中理解的,看起来我已经明白了 :) 再次感谢,这很棒! - Smokescreen
很好的答案,但这假设所有关联数组都按相同方式排序(关联键以相同顺序),否则将无法按预期工作... - qdev
这种方法对我帮助很大,但在我的情况下,我必须注意数组中每个元素的数据类型,当数组被序列化时,一个数组中的ID是整数而另一个数组中的ID是字符串,因此找不到匹配项。 - Antonycx

4

@AbraCadaver提供的解决方案非常好,但正如我在评论中所述,有时候关联数组的元素不会按照相同的顺序出现,因此编写一个自定义函数先按索引/键排序它们是很方便的:

function sortAndSerialize($arr){
    ksort($arr);
    return serialize($arr);
}

array_map('unserialize', array_diff(array_map('sortAndSerialize', $pageids), array_map('sortAndSerialize', $parentpage)));

2

正确的方式 https://github.com/yapro/helpers/blob/master/src/ArrayHelper.php

class ArrayHelper
{
    /**
     * @param array $array1
     * @param array $array2
     * @return array
     */
    function arrayDiffAssocMultidimensional(array $array1, array $array2): array
    {
        $difference = [];
        foreach ($array1 as $key => $value) {
            if (is_array($value)) {
                if (!array_key_exists($key, $array2)) {
                    $difference[$key] = $value;
                } elseif (!is_array($array2[$key])) {
                    $difference[$key] = $value;
                } else {
                    $multidimensionalDiff = $this->arrayDiffAssocMultidimensional($value, $array2[$key]);
                    if (count($multidimensionalDiff) > 0) {
                        $difference[$key] = $multidimensionalDiff;
                    }
                }
            } else {
                if (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
                    $difference[$key] = $value;
                }
            }
        }
        return $difference;
    }
}

1
优秀的答案来自@AbraCadaver,@qdev也有非常敏锐的评论。我的建议只是对@qdev已经提出的答案进行小的调整,使其更易于移植。将该函数分配给变量也使其可在类方法等内部使用。
$sortAndSerialize = function ($arr) 
{
    ksort($arr); 
    return serialize($arr);
};

$pageWithNoChildren = array_map(
    'unserialize',
    array_diff(array_map($sortAndSerialize, $pageids),
               array_map($sortAndSerialize, $parentpage))
);

0
最简单的方法是调用array_udiff(),利用回调函数进行三路比较(无迭代函数调用,无序列化),对行进行操作。
如果行具有不同顺序的关联键,则此方法仍然有效--无需排序。
代码:(演示)
$pageids = [
    ['id' => 1, 'linklabel' => 'Home', 'url' => 'home'],
    ['id' => 2, 'linklabel' => 'Graphic Design', 'url' => 'graphicdesign'],
    ['id' => 3, 'linklabel' => 'Other Design', 'url' => 'otherdesign'],
    ['id' => 6, 'linklabel' => 'Logo Design', 'url' => 'logodesign'],
    ['id' => 15, 'linklabel' => 'Content Writing', 'url' => 'contentwriting'],
];

$parentpage = [
    ['id' => 2, 'linklabel' => 'Graphic Design', 'url' => 'graphicdesign'],
    ['url' => 'otherdesign', 'id' => 3, 'linklabel' => 'Other Design'],
];

var_export(
    array_udiff($pageids, $parentpage, fn($a, $b) => $a <=> $b)
);

输出:

array (
  0 => 
  array (
    'id' => 1,
    'linklabel' => 'Home',
    'url' => 'home',
  ),
  3 => 
  array (
    'id' => 6,
    'linklabel' => 'Logo Design',
    'url' => 'logodesign',
  ),
  4 => 
  array (
    'id' => 15,
    'linklabel' => 'Content Writing',
    'url' => 'contentwriting',
  ),
)

鉴于提问者的样本数据没有表明子数组键已经洗牌,我的样本输入将会干扰@AbraCadaver和@Lebnik的算法,导致它们给出与预期不同的结果。我的代码片段与@qdev和@Gruber的答案给出相同的结果,但是我的代码片段要少得多。


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