рекурсивный array_diff ()?

Я ищу некоторый инструмент, чтобы дать мне рекурсивный diff двух массивов. То, что я представляю, представляет собой веб-страницу с двумя цветными древовидными структурами. На каждом дереве зеленые – это части массива, которые совпадают в обоих массивах, а красный – для частей каждого, которые не соответствуют другому. Что-то вроде выхода dBug

У меня есть код, который дает мне вложенный массив для заполнения отчета. Я разрабатываю новый метод, который должен быть быстрее, но мне нужно проверить значения, а также структуру, чтобы убедиться, что она дает результат, идентичный старому.

Есть ли что-то, что я могу использовать? Или мне нужно написать это? Или есть другой способ достичь моих целей?

Существует одна такая функция, реализованная в комментариях 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; } 

Реализация обрабатывает одновременно только два массива, но я не думаю, что это действительно проблема. Вы можете запустить diff последовательно, если вам нужно разделить 3 или более массивов за раз. Также этот метод использует проверку ключей и делает свободную проверку.

Принятый ответ близок к правильному, но он действительно не эмулирует array_diff правильно.

Есть две проблемы, которые в значительной степени связаны с сопоставлением ключей:

  1. array_diff имеет конкретное поведение, когда он не дает результата для ключа массива, который полностью отсутствует во втором массиве, если его значение все еще находится во втором массиве. Если у вас есть два массива $first = ['foo' => 2, 'moo' => 2] и $second = ['foo' => 2] , используя функцию принятого ответа, выход будет ['moo' => 2] . Если вы запускаете одни и те же массивы с помощью array_diff , это приведет к созданию пустого массива. Это связано с тем, else выражение final else выше этой функции добавляет его в diff, если отсутствует массив, но это не ожидаемое поведение от array_diff . То же самое верно для этих двух массивов: $first = ['foo' => 1] и $second = [1] . array_diff создаст пустой массив.

  2. Если два массива имеют одинаковые значения, но разные ключи, он возвращает больше значений, чем ожидалось. Если у вас есть два массива $foo = [1, 2] и $moo = [2, 1] , функция из принятого ответа выведет все значения из $foo . Это связано с тем, что на каждой итерации выполняется строгое сопоставление ключей, где он находит один и тот же ключ (числовой или другой) в обоих массивах вместо проверки всех других значений во втором массиве.

Следующая функция аналогична, но более точно работает с тем, как вы ожидаете, что 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; } 
 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; } 

Пример:

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

Попробуйте этот код:

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