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


Get difference between associative rows of two 2-dimensional arrays

我有两个数组,这些数组包含有关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] 键,因此它忽略它们并返回从 [2] 开始$pageids的所有信息。但是,我希望它查看嵌套数组的内容并比较这些内容,例如我需要它来查看哪些idlinklabelurl $pageids而不是$parentpages并返回这些值。

如何让array_diff_assoc()在嵌套数组的键上运行,而不是在第一个数组的键上运行,因此最终结果是一个包含 [0]、[3] 和 [4] 数组内容的数组 $pageids

预期成果:

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',
  ),
)

要检查多点,请尝试以下操作:

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

质检部

@AbraCadaver非常好的解决方案,但就像我在评论中所说的那样,在某些情况下,关联数组的元素在任何地方的顺序都不相同,因此首先按索引/键对它们进行排序的自定义函数很方便:

function sortAndSerialize($arr){
    ksort($arr);
    return serialize($arr);
}
array_map('unserialize', array_diff(array_map('sortAndSerialize', $pageids), array_map('sortAndSerialize', $parentpage)));

正确的方式 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;
    }
}

@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))
);

最简单的是,调用 array_udiff() 以利用对行进行 3 向比较(无迭代函数调用,无序列化(的回调。

如果行具有不同顺序的关联键,这仍然有效 - 无需排序。

代码:(演示(

$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的答案相同,但我的片段所做的工作要少得多。