Намиране на разлики в многомерни масиви?

streleca_stz

Registered
Здравейте,
Опитвам се да проверя дали 2 многомерни масива се различават един спрямо друг и да извадя всички редове, които се различават. Проблемът е, че стигнах до положението, в което проверявам за разлики в стойностите на масивите от първо ниво, но навътре ако има разлики няма да ги отчете. Ето пример:
PHP:
$arr1 = array(
	'key1' => 2,
	'key2' => 4,
	'key3' => array(1,5,2,7),
	'key4' => 1,
);

$arr2 = array(
	'key1' => 2,
	'key2' => 5,
	'key3' => array(1,2,7),
	'key4' => 5,
);

$diff = array_diff(array_merge($arr1, $arr2), array_intersect($arr1,$arr2));
В случая $diff ще върне:
PHP:
Array
(
    [key2] => 5
    [key4] => 5
)
което ме устройва, но до известна степен, защото масивът в 'key3' също има разлики, които не ги намира. Ще се радвам ако някой може да съдейства как мога да допълня вече измисленото, за да търси от всички нива за разлики в стойностите. :)
 
PHP:
<?php

$arr1 = array(
        'key1' => 2,
        'key2' => 4,
        'key3' => array(1,5,2,7),
        'key4' => 1,
);

$arr2 = array(
        'key1' => 2,
        'key2' => 5,
        'key3' => array(1,2,7),
        'key4' => 5,
);

function value_comparison($a, $b) {
    if ( is_array($a) && is_array($b) ) {
        $diff = array_diff($a, $b);
        if ( sizeof($diff) > 0 ) return -1;
        else return 0;
    } else {
        if ( $a === $b ) {
            return 0;   
        }
        return ($a > $b) ? 1 : -1;
    }
}

function key_comparison($a, $b) {
    if ( $a === $b ) return 0;
    return ($a > $b) ? 1 : -1;
}

$diff = array_udiff_uassoc($arr1, $arr2, "value_comparison", "key_comparison");

print_r($diff);

Това би трябвало да ти свърши работа.
 
@Fakeheal сварих да ти прочета мнението.

PHP:
function value_comparison($a, $b) {
    if ( is_array($a) && is_array($b) ) {
        $diff = array_udiff_assoc($a, $b, "value_comparison");
        if ( sizeof($diff) > 0 ) return -1;
        else return 0;
    } else {
        if ( $a === $b ) {
            return 0;   
        }
        return ($a > $b) ? 1 : -1;
    }
}
 
Резултат след промяната.

PHP:
Array 1:
Array
(
    [key1] => 2
    [key2] => 4
    [key3] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 7
            [3] => Array
                (
                    [0] => 1
                    [1] => 4
                    [2] => 3
                )

        )

    [key4] => 1
)


Array 2:
Array
(
    [key1] => 2
    [key2] => 5
    [key3] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 7
            [3] => Array
                (
                    [0] => 1
                    [1] => 2
                    [2] => 3
                )

        )

    [key4] => 5
)


Differences:
Array
(
    [key2] => 4
    [key3] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 7
            [3] => Array
                (
                    [0] => 1
                    [1] => 4
                    [2] => 3
                )

        )

    [key4] => 1
)

П.П. Дадох резултат с грешни данни.
 
При мен това:

Код:
<?php

$arr1 = array(
        'key1' => 2,
        'key2' => 4,
        'key3' => array(1,5,2,7),
        'key4' => 1,
);

$arr2 = array(
        'key1' => 2,
        'key2' => 5,
        'key3' => array(1,2, array(1,4,4,5, array(10, 15, 20)), 7), 
        'key4' => 5,
);

function value_comparison($a, $b) {
    if ( is_array($a) && is_array($b) ) {
        $diff = array_udiff_assoc($a, $b, "value_comparison");
        if ( sizeof($diff) > 0 ) return -1;
        else return 0;
    } else {
        if ( $a === $b ) {
            return 0;   
        }
        return ($a > $b) ? 1 : -1;
    }
}

function key_comparison($a, $b) {
    if ( $a === $b ) return 0;
    return ($a > $b) ? 1 : -1;
}

$diff = array_udiff_uassoc($arr1, $arr2, "value_comparison", "key_comparison");

print_r($diff);

Връща:

Код:
Array
(
    [key2] => 4
    [key3] => Array
        (
            [0] => 1
            [1] => 5
            [2] => 2
            [3] => 7
        )

    [key4] => 1
)

Къде ми е грешката?

7 не трябва ли да не е разликата тъй като позицията и стойността е еднаква?
 
Ами реално няма проблем в ситуацията. Просто вади целия масив, защото не е същия като във втория масив.

Пробвай следното. Направи един тест като направиш key3 с еднакви масиви и дълбочини. Да са идентични.
После направи следния тест: на един от двата масива направи промяна в най-вътрешния масив и като разлики ще ти даде отново целия key3 масив от $arr1.
Вероятно ще трябва да се напише изцяло нов алгоритъм, за да може да показва само разликите в дълбочина.

П.П. Въпроса е, нужно ли му е с точност да знае разликите във вътрешните масиви или просто иска да знае, че там има разлики.
 
Ако иска, може да пробва с рекурсия, не знам дали е оптималният вариант

https://stackoverflow.com/questions/12246039/multidimensional-array-difference-php

Грешка, горният код не работи с дълбочина>2

Edit2: но по-надолу от първия отговор има работещи
 
ttta каза:
Ми ако искат, то си е задължително да се ползва рекурсия. Каквато се ползва в горния код...

Много весел форум, ей...

Имах предвид рекурсия без готовите diff функции.



Лошо. Бедния речников запас се преодолява с четене на повечко литература - художествена.

Явно не си чел достатъчно, иначе щеше да знаеш кога се използва пълен и кратък член.
 
ttta каза:
Fakeheal каза:
ttta каза:
Ми ако искат, то си е задължително да се ползва рекурсия. Каквато се ползва в горния код...

Много весел форум, ей...
аз само мога да кажа да ходиш да се гръмнеш, лол
Лошо. Бедния речников запас се преодолява с четене на повечко литература - художествена.

Ама кажи честно, след като се занимаваш от поне 7 години с програмиране, наистина ли не можеш да видиш рекурсивното извикване?
За очевадните грешки няма да питам, щото гражданина, автор, трудно преглъща критика...

Ама хайде дай най-накрая код, та да се научим и ние. Дай да видим твоето решение. То философията е най-лесна.
 
Да, по неговата логика. :D


Иначе, ето решение.
PHP:
$arr1 = array(
        'key1' => 2,
        'key2' => 4,
        'key3' => array(1, 2, 
                        array(1,4,3,5, 
                              array(10, 13, 20)),
                        7),
        'key4' => 1,
);

$arr2 = array(
        'key1' => 2,
        'key2' => 5,
        'key3' => array(1,2,
                        array(1,4,4,5, 
                              array(10, 15, 21)), 
                        7), 
        'key4' => 5,
);

function array_diff_recursive($a1, $a2) {
    $result = array();
    
    foreach( $a1 as $k=>$v ) {
        if ( array_key_exists($k, $a2) && (is_array($v) && is_array($a2[$k])) ) {
            $result[$k] = array_diff_recursive($v, $a2[$k]);
        } else {
            if ( !isset($a2[$k]) || $v !== $a2[$k] ) {
                $result[$k] = $v;
            }
        }
    }
    
    return $result;
}

$multi_diff = array_diff_recursive($arr1, $arr2);

Резултат:
PHP:
Array 1:
Array
(
    [key1] => 2
    [key2] => 4
    [key3] => Array
        (
            [0] => 1
            [1] => 2
            [2] => Array
                (
                    [0] => 1
                    [1] => 4
                    [2] => 3
                    [3] => 5
                    [4] => Array
                        (
                            [0] => 10
                            [1] => 13
                            [2] => 20
                        )

                )

            [3] => 7
        )

    [key4] => 1
)


Array 2:
Array
(
    [key1] => 2
    [key2] => 5
    [key3] => Array
        (
            [0] => 1
            [1] => 2
            [2] => Array
                (
                    [0] => 1
                    [1] => 4
                    [2] => 4
                    [3] => 5
                    [4] => Array
                        (
                            [0] => 10
                            [1] => 15
                            [2] => 21
                        )

                )

            [3] => 7
        )

    [key4] => 5
)


Multi diff:
Array
(
    [key2] => 4
    [key3] => Array
        (
            [2] => Array
                (
                    [2] => 3
                    [4] => Array
                        (
                            [1] => 13
                            [2] => 20
                        )

                )

        )

    [key4] => 1
)

ЕДИТ: Малко промяна по кода. Махнах някои излишни проверки.
 
Ами всички работят, но не точно, защото ако да речем в първи масив липсва key3, а във втория е наличен - то тогава не го намира като разлика... С които и примери да пробвах все се сблъсквах с този проблем (дори и тези от stackoverflow)
 
Това мисля, че вече ще ти свърши работа.

PHP:
function array_diff_recursive($a1, $a2) {
    $result = array();
    $loopArray = (sizeof($a1) >= sizeof($a2)) ? $a1 : $a2;
    $len = sizeof($loopArray);

    $quit = false;
    for ( $i = 0; $i < $len; $i++ ) {
        $oppositeArray = ($loopArray === $a1) ? $a2 : $a1;
        $oppositeArrayKeys = array_keys($oppositeArray);
        $loopArrayKeys = array_keys($loopArray);

        if ( array_key_exists($loopArrayKeys[$i], $oppositeArray) ) {
            if ( is_array($loopArray[$loopArrayKeys[$i]]) && is_array($oppositeArray[$loopArrayKeys[$i]]) ) {
                $result[$loopArrayKeys[$i]] = array_diff_recursive($loopArray[$loopArrayKeys[$i]], $oppositeArray[$loopArrayKeys[$i]]);
            }
            else {
                if ( $loopArray[$loopArrayKeys[$i]] !== $oppositeArray[$loopArrayKeys[$i]] ) {
                    $result[$loopArrayKeys[$i]] = $loopArray[$loopArrayKeys[$i]];
                }
            }
        } else {
            $result[$loopArrayKeys[$i]] = $loopArray[$loopArrayKeys[$i]];
        }

        if ( $i == ($len-1) && !$quit ) {
            $temp = $oppositeArray;
            $oppositeArray = $loopArray;
            $loopArray = $temp;
            $i = 0;
            $quit = true;
            $len = sizeof($loopArray);
        }
    }
    
    return $result;
}
 

Горе