Php 递归数组_diff()?
我正在寻找一些工具来给我两个数组的递归差异。我设想的是一个具有两种颜色编码树结构的网页。在每个树上,绿色表示两个数组中匹配的数组部分,红色表示两个数组中不匹配的部分。类似于dBug的输出 我有一些代码,它为我提供了一个嵌套数组来填充报表。我正在开发一种新方法,它应该更快,但我需要测试值和结构,以确保它提供与旧方法相同的输出Php 递归数组_diff()?,php,arrays,recursion,diff,Php,Arrays,Recursion,Diff,我正在寻找一些工具来给我两个数组的递归差异。我设想的是一个具有两种颜色编码树结构的网页。在每个树上,绿色表示两个数组中匹配的数组部分,红色表示两个数组中不匹配的部分。类似于dBug的输出 我有一些代码,它为我提供了一个嵌套数组来填充报表。我正在开发一种新方法,它应该更快,但我需要测试值和结构,以确保它提供与旧方法相同的输出 有什么我可以用的吗?还是我需要写这个?还是有其他方法可以实现我的目标?的评论中实现了一个这样的功能 该实现一次只处理两个数组,但我认为这并不存在问题。如果一次需要3个或更多阵
有什么我可以用的吗?还是我需要写这个?还是有其他方法可以实现我的目标?的评论中实现了一个这样的功能
该实现一次只处理两个数组,但我认为这并不存在问题。如果一次需要3个或更多阵列的差异,可以按顺序运行差异。此外,此方法使用密钥检查并进行松散验证。接受的答案接近正确,但它并没有真正正确地模拟数组 有两个问题主要围绕着密钥匹配:
array\u diff
具有一种特定行为,即如果第二个数组中的值仍在第二个数组中,它不会为第二个数组中完全缺失的数组键生成结果。如果您有两个数组$first=['foo'=>2,'moo'=>2]
和$second=['foo'=>2]
,使用接受答案的函数,输出将是['moo'=>2]
。如果通过array\u diff
运行相同的数组,它将生成一个空数组。这是因为如果缺少数组键,上述函数的finalelse
语句会将其添加到diff中,但这不是array\u diff
的预期行为。这两个数组也是如此:$first=['foo'=>1]
和$second=[1]
<代码>数组_diff将生成一个空数组$foo=[1,2]
和$moo=[2,1]
,则接受答案中的函数将输出$foo
中的所有值。这是因为它在每次迭代中进行严格的键匹配,在两个数组中找到相同的键(数字或其他),而不是检查第二个数组中的所有其他值array_diff
的工作方式(也适用于不那么愚蠢的变量名):
请尝试以下代码:
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);
示例:
$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'
)
);
array_diff_assoc_recursive($a,$b);
Array
(
[product_a] => Array
(
[color] => Red
[serial] => Array
(
[2] => 3
)
)
)
输出:
$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'
)
);
array_diff_assoc_recursive($a,$b);
Array
(
[product_a] => Array
(
[color] => Red
[serial] => Array
(
[2] => 3
)
)
)
by的答案很有效,只是需要在线更改:
$difference[$newKey][$firstKey] = $secondArray[$firstKey];
与:
或者,如果您使用的是Laravel,则:
$difference[$newKey][$firstKey] = array_get($secondArray, $firstKey);
否则,将出现如下错误
PHP错误:未定义索引:某些\u键
当$secondArray中存在some_键而$firstArray中不存在时只是为了暂时测试这些输出,还是为了长期使用?这是一个测试,一个简单的
wdiff
overvar\u导出
输出应该会起作用……在嵌套结构中,如果一个元素是一个6的数组,而另一个是一个3的数组,那么它会跳起来吗?因为在输出中,比如说从第0-30行,它将是相同的,从最后回到第36行,它将是相同的。只有那些中间线会有所不同——3对6。如果wdiff看到这一点,它会被绊倒吗?输出不会很好地分成键/值对,但它会在进一步匹配之前和之后努力匹配行,而且,如果我只是分散检查,它会这样做。只要用一个简单的例子,看看它是否适合你的目的。另一种方法是递归函数,也不难,但需要更多的工作。只是一个想法:如果你需要一些非常快速的东西,你可以先用json_encode将其转换为字符串进行测试,比较两个字符串,如果有差异,然后进行递归检查。@Zend_Sklave,因为mhitza的答案对你有用,你也许应该把它标记为真正响应了你的请求…@JonL。我认为他必须是这个问题的作者,才能做到这一点:)这个函数返回许多根本没有改变的数据。我看不出这有什么用。此外,如果你真的想得到两个数组之间的差异,你需要运行这个函数两次,不仅要找到什么是数组1的一部分而不是数组2的一部分,还要找到什么是数组2的一部分而不是数组1的一部分。对某些人来说可能是显而易见的。。。但不是对其他人(像我一开始;)@CommaToast您能提供一个示例,说明它何时返回未更改的数据吗?对于我的两个测试,它只返回差异。你能解释一下结果有什么不同吗?对于我的测试,我得到了完全相同的结果。Thanks@JeffPuckettII对不起,我没有给你一个很好的解释。我已经更新了答案,解释了接受的答案与数组_diff
的区别。刚刚在上检查了简单示例,它对简单数组的工作(行为)与预期(编辑)相同。但是递归并不像它应该的那样工作:(如果我们有值作为对象的关联数组,它就不起作用。例如,$a=[“foo”=>(object)[“p1”=>1,“p2”=>2],“moo”=>(object)[“p3”=>3]
,$b=[“foo”=>(object)[“p4”=>4]
。有时考虑[1,2]和[2,1]不同并不是一个需要的愿望。数组不是元素顺序不重要的集合。PHP的数组可以表示很多东西。区分关联数组(键为任何类型)和常规数组(键为整数)并不容易。常规数组[1,2]
被认为与数组[2,1]不同
。这就是为什么我们有向数组的开头或结尾添加元素的函数,而不仅仅是向数组添加元素的函数(
$difference[$newKey][$firstKey] = array_key_exists($firstKey, $secondArray) ? $secondArray[$firstKey] : null;
$difference[$newKey][$firstKey] = array_get($secondArray, $firstKey);