php 递归array_diff()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3876435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 11:22:15  来源:igfitidea点击:

recursive array_diff()?

phparraysrecursiondiff

提问by user151841

I'm looking for some tool to give me a recursive diff of two arrays. What I envision is a web page with two color-coded tree-structures. On each tree, green are parts of the array which match in both arrays, and red is for parts of each that don't match the other. Something like the output of dBug

我正在寻找一些工具来为我提供两个数组的递归差异。我设想的是一个带有两种颜色编码树结构的网页。在每棵树上,绿色是数组中在两个数组中都匹配的部分,红色是每个数组中不匹配的部分。类似于dbug的输出

I have some code that gives me a nested array to populate a report. I'm developing a new method that should be faster, but I need to test the values and also the structure, to make sure it gives output identical to the old method.

我有一些代码为我提供了一个嵌套数组来填充报告。我正在开发一种应该更快的新方法,但我需要测试值和结构,以确保它提供与旧方法相同的输出。

Is there something out there that I can use? Or do I need to write this? Or is there another way to accomplish my goals?

有什么东西可以使用吗?还是我需要写这个?或者还有其他方法可以实现我的目标吗?

回答by mhitza

There is one such function implemented in the comments of array_diff.

array_diff的注释中实现了一个这样的函数。

function arrayRecursiveDiff($aArray1, $aArray2) {
  $aReturn = array();

  foreach ($aArray1 as $mKey => $mValue) {
    if (array_key_exists($mKey, $aArray2)) {
      if (is_array($mValue)) {
        $aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]);
        if (count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; }
      } else {
        if ($mValue != $aArray2[$mKey]) {
          $aReturn[$mKey] = $mValue;
        }
      }
    } else {
      $aReturn[$mKey] = $mValue;
    }
  }
  return $aReturn;
} 

The implementation only handles two arrays at a time, but I do not think that really posses a problem. You could run the diff sequentially if you need the diff of 3 or more arrays at a time. Also this method uses key checks and does a loose verification.

该实现一次只处理两个数组,但我认为这并没有真正的问题。如果您一次需要 3 个或更多数组的差异,您可以按顺序运行差异。此外,此方法使用密钥检查并进行松散验证。

回答by treeface

The accepted answer is close to correct, but it doesn't really emulate array_diffcorrectly.

接受的答案接近正确,但它并没有真正array_diff正确地模拟。

There are two problems that largely revolve around key matching:

有两个问题主要围绕密钥匹配:

  1. array_diffhas a specific behavior where it does not produce a result for an array key that is completely missing from the second array if its valueis still in the second array. If you have two arrays $first = ['foo' => 2, 'moo' => 2]and $second = ['foo' => 2], using the accepted answer's function the output will be ['moo' => 2]. If you run the same arrays through array_diff, it will produce an empty array. This is because the above function's final elsestatement adds it to the diff if the array key is missing, but that's not the expected behavior from array_diff. The same is true with these two arrays: $first = ['foo' => 1]and $second = [1]. array_diffwill produce an empty array.

  2. If two arrays have the same values but different keys, it returns more values than expected. If you have two arrays $foo = [1, 2]and $moo = [2, 1], the function from the accepted answer will output all values from $foo. This is because it's doing a strict key matching on each iteration where it finds the same key (numerical or otherwise) in both arrays instead of checking all of the other values in the second array.

  1. array_diff有一个特定的行为,如果它的仍然在第二个数组中,它不会为第二个数组中完全丢失的数组键生成结果。如果您有两个数组$first = ['foo' => 2, 'moo' => 2]and $second = ['foo' => 2],使用接受的答案的函数,输出将为['moo' => 2]。如果您通过 运行相同的数组array_diff,它将产生一个空数组。这是因为else如果缺少数组键,上述函数的最终语句会将其添加到 diff 中,但这不是array_diff. 这两个数组也是如此:$first = ['foo' => 1]$second = [1]array_diff将产生一个空数组。

  2. 如果两个数组具有相同的值但不同的键,则返回的值比预期的多。如果您有两个数组$foo = [1, 2]and $moo = [2, 1],则接受答案中的函数将输出 中的所有值$foo。这是因为它在每次迭代中都进行严格的键匹配,它在两个数组中找到相同的键(数字或其他),而不是检查第二个数组中的所有其他值。

The following function is similar, but acts more closely to how you'd expect array_diffto work (also with less silly variable names):

以下函数类似,但更接近您期望array_diff的工作方式(也使用不那么愚蠢的变量名称):

function array_diff_recursive($arr1, $arr2)
{
    $outputDiff = [];

    foreach ($arr1 as $key => $value)
    {
        //if the key exists in the second array, recursively call this function 
        //if it is an array, otherwise check if the value is in arr2
        if (array_key_exists($key, $arr2))
        {
            if (is_array($value))
            {
                $recursiveDiff = array_diff_recursive($value, $arr2[$key]);

                if (count($recursiveDiff))
                {
                    $outputDiff[$key] = $recursiveDiff;
                }
            }
            else if (!in_array($value, $arr2))
            {
                $outputDiff[$key] = $value;
            }
        }
        //if the key is not in the second array, check if the value is in 
        //the second array (this is a quirk of how array_diff works)
        else if (!in_array($value, $arr2))
        {
            $outputDiff[$key] = $value;
        }
    }

    return $outputDiff;
}

回答by JRodryB

function array_diff_assoc_recursive($array1, $array2)
{
    foreach($array1 as $key => $value){

        if(is_array($value)){
            if(!isset($array2[$key]))
            {
                $difference[$key] = $value;
            }
            elseif(!is_array($array2[$key]))
            {
                $difference[$key] = $value;
            }
            else
            {
                $new_diff = array_diff_assoc_recursive($value, $array2[$key]);
                if($new_diff != FALSE)
                {
                    $difference[$key] = $new_diff;
                }
            }
        }
        elseif((!isset($array2[$key]) || $array2[$key] != $value) && !($array2[$key]===null && $value===null))
        {
            $difference[$key] = $value;
        }
    }
    return !isset($difference) ? 0 : $difference;
}

Example:

例子:

$a = array(
    "product_a" => array(
        'description'=>'Product A',
        'color'=>'Red',
        'quantity'=>'5',
        'serial'=>array(1,2,3)
    ),
    "product_b" => array(
        'description'=>'Product B'
    )
);

$b = array(
    "product_a" => array(
        'description'=>'Product A',
        'color'=>'Blue',
        'quantity'=>'5',
        'serial'=>array(1,2,5)
    ),
    "product_b" => array(
        'description'=>'Product B'
    )
);

Output:

输出:

array_diff_assoc_recursive($a,$b);

Array
(
    [product_a] => Array
        (
            [color] => Red
            [serial] => Array
                (
                    [2] => 3
                )    
        )    
)

回答by M Rostami

Try this code:

试试这个代码:

function arrayDiffRecursive($firstArray, $secondArray, $reverseKey = false)
{
    $oldKey = 'old';
    $newKey = 'new';
    if ($reverseKey) {
        $oldKey = 'new';
        $newKey = 'old';
    }
    $difference = [];
    foreach ($firstArray as $firstKey => $firstValue) {
        if (is_array($firstValue)) {
            if (!array_key_exists($firstKey, $secondArray) || !is_array($secondArray[$firstKey])) {
                $difference[$oldKey][$firstKey] = $firstValue;
                $difference[$newKey][$firstKey] = '';
            } else {
                $newDiff = arrayDiffRecursive($firstValue, $secondArray[$firstKey], $reverseKey);
                if (!empty($newDiff)) {
                    $difference[$oldKey][$firstKey] = $newDiff[$oldKey];
                    $difference[$newKey][$firstKey] = $newDiff[$newKey];
                }
            }
        } else {
            if (!array_key_exists($firstKey, $secondArray) || $secondArray[$firstKey] != $firstValue) {
                $difference[$oldKey][$firstKey] = $firstValue;
                $difference[$newKey][$firstKey] = $secondArray[$firstKey];
            }
        }
    }
    return $difference;
}

$differences = array_replace_recursive(
    arrayDiffRecursive($firstArray, $secondArray),
    arrayDiffRecursive($secondArray, $firstArray, true)
);
var_dump($differences);

回答by jfeid

The answer by Mohamadis working good, except that it needs change on the line:

Mohamad的答案效果很好,只是它需要在线更改:

$difference[$newKey][$firstKey] = $secondArray[$firstKey];

with:

和:

$difference[$newKey][$firstKey] = array_key_exists($firstKey, $secondArray) ? $secondArray[$firstKey] : null;

or, if you are using Laravel, with:

或者,如果您使用的是 Laravel,请使用:

$difference[$newKey][$firstKey] = array_get($secondArray, $firstKey);

Otherwise, you will get errors like

否则,你会得到类似的错误

PHP error: Undefined index: some_key

PHP 错误:未定义索引:some_key

when a some_key exists in $secondArray but not in $firstArray

当 some_key 存在于 $secondArray 但不在 $firstArray 中时