Notatki PHP

prywatne zapiski na kamieniu

Porównywanie tablic by ustalić wyjątkowe i unikalne elementy pierwszej tablicy, których nie ma w kolejnych tablicach.

array_diff (array tabela1, array tabela2 [, array ...])

Zwraca tablicę zawierającą wszystkie wartości tablicy tabela1, które nie są obecne w innych tablicach-argumentach. Zachowywane są przy tym klucze.   

Mając dwie tablice, np.: A := {a1, ..., an} oraz B:= {a1, b1, ... , bm}

=> array_diff(A,B) = {a2, ..., an}


co oznacza, że


array_diff(A,B) zwróci nam wszystkie elementy tablicy A, które nie występują w tablicy B.

 

 
<?php
$tablica1 = array ("a" => "zielony", "czerwony", "niebieski", "czerwony");
$tablica2 = array ("b" => "zielony", "żółty", "czerwony");
$wynik = array_diff ($tablica1, $tablica2);
 
print_r($wynik);
?>
 
 
Array
(
    [1] => niebieski
)

Dwa elementy tablicy uważane są za identyczne wtedy i tylko wtedy jeśli

(string) $element1 === (string) $element2.

Słownie: kiedy reprezentacje elementów w postaci stringów są identyczne.

 

Czasami przydają się jako wynik porównania tablic elementy występujące w nich kolejno jako unikalne:

 
$tablica1 = array ("a" => "zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica2 = array ("b" => "zielony", "żółty", "czerwony");
 
function arrayDiff($A, $B) {
    $intersect = array_intersect($A, $B);
    return array_merge(array_diff($A, $intersect), array_diff($B, $intersect));
}
 
print_r(arrayDiff($tablica1, $tablica2));
 
Array ( [0] => niebieski [1] => fioletowy [2] => żółty ) 

Wynikiem jest unikalny element pierwszej tablicy niebieski, fioletowy, oraz żółty w drugiej tablicy.

 

Funkcję tę możemy wykorzystać nieoczekiwanie do skasowania elementu tylko drugiej tablicy:

 
$tablica1 = array ("a" => "zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica2 = array ("b" => "zielony", "żółty", "czerwony");
 
//pass value you wish to delete and the array to delete from
function array_delete( $value, $array)
{
    $array = array_diff( $array, array($value) );
    return $array;
}
print_r(array_delete("zielony", $tablica2));
 
Array ( [0] => żółty [1] => czerwony ) 

 

Rekursywnie:

 
$tablica1 = array ("zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica2 = array ("zielony");
 
 
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;
} 
 
print_r(arrayRecursiveDiff($tablica1, $tablica2));

 Wyeliminowaliśmy kolor zielony podany z tablicy2, zostaje:

 
Array ( [1] => czerwony [2] => niebieski [3] => czerwony [4] => fioletowy ) 

      

Uwaga. Podobne działanie do array_diff możemy uzyskać przy pomocy kilka razy szybszej funkcji:

 
$tablica1 = array ("zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica2 = array ("zielony", "żółty", "czerwony");
 
function my_array_diff($arrayFrom, $arrayAgainst)
    {
        $arrayAgainst = array_flip($arrayAgainst);
 
        foreach ($arrayFrom as $key => $value) {
            if(isset($arrayAgainst[$value])) {
                unset($arrayFrom[$key]);
            }
        }
 
        return $arrayFrom;
    }
 
 
print_r(my_array_diff($tablica1, $tablica2));
 
Array ( [2] => niebieski [4] => fioletowy ) 

Czas pomiaru różnic czasowych w wykonaniu tych funkcji, oryginalnej i napisanej, możemy uzyskać i sobie porównać:

 
echo '<br>';
$t = microtime(true); $a = range(0,25000); $b = range(15000,500000); $c = array_diff($a, $b); echo microtime(true) - $t;
echo '<br>';
$t = microtime(true); $a = range(0,25000); $b = range(15000,500000); $c = my_array_diff($a, $b); echo microtime(true) - $t;
echo '<br>';

 

Czasami zachodzi potrzeba, by tablica wynikowa miała klucze zaczynające się od początku i kolejno tylko dla wszystkich elementów wynikowych nowej tablicy z porównania dwóch:

 
$tablica4 = array ("a" => "zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica5 = array ("b" => "zielony", "żółty", "czerwony");
 
function array_diff_from_zero($array1, $array2){
    # This wrapper for array_diff rekeys the array returned
    $valid_array = array_diff($array1,$array2);
 
    # reinstantiate $array1 variable
    $array1 = array();
 
    # loop through the validated array and move elements to $array1
    # this is necessary because the array_diff function returns arrays that retain their original keys
    foreach ($valid_array as $valid){
        $array1[] = $valid;
        }
    return $array1;
    }
 
print_r(array_diff_from_zero($tablica4, $tablica5));
echo '<br>';
 
Array ( [0] => niebieski [1] => fioletowy ) 

 

Czasami mamy tablicę2 wzorca o tych samych kluczach, jakie mogą pojawić się w tablicy1 badanej. Kolejna funkcja wyeliminuje elementy tablicy1 której klucze wystąpią w tablicy2 wzorca.

 
 
$tablica1 = array ("zielony", "czerwony", "niebieski", "czarny", "fioletowy");
$tablica2 = array ("zielony", "żółty", "czerwony");
$c = array_key_diff ($tablica1, $tablica2); 
print_r($c);
 
function array_key_diff($ar1, $ar2) {  // , $ar3, $ar4, ...
    // returns copy of array $ar1 with those entries removed
    // whose keys appear as keys in any of the other function args
    $aSubtrahends = array_slice(func_get_args(),1);
    foreach ($ar1 as $key => $val)
        foreach ($aSubtrahends as $aSubtrahend)
            if (array_key_exists($key, $aSubtrahend))
                unset ($ar1[$key]);
    return $ar1;
}
 
Array ( [3] => czarny [4] => fioletowy ) 

 

Weźmy następujące tablice:

 
 
$tablica1 = array ("zielony", "czerwony", "niebieski", "czarny", "fioletowy");
$tablica2 = array ("zielony", "żółty", "czerwony");
 
$tablica4 = array ("a" => "zielony", "czerwony", "niebieski", "czerwony", "fioletowy");
$tablica5 = array ("b" => "zielony", "żółty", "czerwony");
 
 
// returns a two dimensions array with the deleted data
// and the added data
function array_diff_both($new,$old)
{
    $del=array_diff_assoc($old,$new);
    $add=array_diff_assoc($new,$old);
    return $diff=array("del"=>$del, "add"=>$add);
}
 
// returns a two dimensions array with the equal data,
// deleted data and the added data
function array_diff_all($arr_new,$arr_old)
{
    $arr_equ=array_intersect_assoc($arr_new,$arr_old);
    $arr_del=array_diff_assoc($arr_old,$arr_new);
    $arr_add=array_diff_assoc($arr_new,$arr_old);
    return $diff=array("equ"=>$arr_equ, "del"=>$arr_del, "add"=>$arr_add);
}
 
$c = array_diff_both ($tablica1, $tablica2); 
print_r($c);
echo '<br>';
 
$c = array_diff_all ($tablica1, $tablica2); 
print_r($c);
echo '<br>';

Otrzymamy efektem porównania:

 
Array 
( 
[del] => Array 
( 
[1] => żółty 
[2] => czerwony 
) 
[add] => Array 
( 
[1] => czerwony [2] => niebieski [3] => czarny [4] => fioletowy 
) 
)
Array (
[equ] => Array 
( 
[0] => zielony 
) 
[del] => Array 
( 
[1] => żółty 
[2] => czerwony 
) 
[add] => Array 
( 
[1] => czerwony 
[2] => niebieski 
[3] => czarny 
[4] => fioletowy 
) 
) 

Dla innego wywołania:

 
 
$c = array_diff_both ($tablica4, $tablica5); 
print_r($c);
echo '<br>';
 
$c = array_diff_all ($tablica4, $tablica5); 
print_r($c);
echo '<br>';
 
Array 
( 
[del] => Array 
( 
[b] => zielony 
[0] => żółty 
[1] => czerwony 
)
[add] => Array 
( 
[a] => zielony 
[0] => czerwony 
[1] => niebieski 
[2] => czerwony 
[3] => fioletowy 
) 
)
Array 
( 
[equ] => Array 
(
) 
[del] => Array 
( 
[b] => zielony 
[0] => żółty 
[1] => czerwony 
) 
[add] => Array 
( 
[a] => zielony 
[0] => czerwony 
[1] => niebieski 
[2] => czerwony 
[3] => fioletowy 
) 
)