18

I have two multidimensional arrays and I want the difference. For eg. I have taken two-dimensional two arrays below

$array1 = Array (
       [a1] => Array  (
          [a_name] => aaaaa
          [a_value] => aaa
     )

       [b1] => Array (
          [b_name] => bbbbb
          [b_value] => bbb
   )
       [c1] => Array (
          [c_name] => ccccc
          [c_value] => ccc
   )

)

$array2 = Array (
 [b1] => Array (
       [b_name]=> zzzzz
     )
)

Now I want the key difference of these two arrays. I have tried array_diff_key() but it doesnot work for multidimensional.

array_diff_key($array1, $array2)

I want the output as following

//output
$array1 = Array (
   [a1] => Array  (
      [a_name] => aaaaa
      [a_value] => aaa
 )

   [b1] => Array (          
      [b_value] => bbb
)
   [c1] => Array (
      [c_name] => ccccc
      [c_value] => ccc
)

)

If you think my question is genuine please accept it and answer. Thank you.

EDIT

Now if the second array is

$array2 = Array( [b1] => zzzzz)

The result should be

$array1 = Array (
   [a1] => Array  (
      [a_name] => aaaaa
      [a_value] => aaa
    )     

   [c1] => Array (
      [c_name] => ccccc
      [c_value] => ccc
     )

)
kcssm
  • 1,727
  • 3
  • 16
  • 19
  • In your expected output you are not compare, but replace `b1`. What do you really want? – s.webbandit Sep 03 '12 at 10:30
  • I want the difference of the two array. The expected output is the difference of the two array, not replace. – kcssm Sep 03 '12 at 10:33
  • 3
    If from 14 answers **none** solved you problems, you might want to reconsider your style of writing a question! – Yoshi Sep 03 '12 at 10:33
  • We assume that your questios were like `here is my task: ... - Can you make it for me please`. This is not a place where people would make something for you. We just can suppose some ideas. – s.webbandit Sep 03 '12 at 10:33
  • If you'd take a look at PHP DOCS (http://ru2.php.net/manual/en/function.array-diff.php) about array differernce you'd see that difference is not what you think it is. `Returns an array containing all the entries from array1 that are not present in any of the other arrays. ` – s.webbandit Sep 03 '12 at 10:35
  • Oh I see. Ok I can explain that. Before I didnot have privilege to accept the answer even if I wanted as stackoverflow needed some minimum score before I can do that. This is the reason some of my early question's answers are not accepted. Its not long time, I have this privilege. So now I will right away accept the appropriate answers. Thanks for reminding me on this. And any help on this is really appreciated. Thanks – kcssm Sep 03 '12 at 10:41
  • I made a composer package to compare multidimensional arrays: https://github.com/rogervila/array-diff-multidimensional – rogervila Jul 23 '21 at 08:42

14 Answers14

17

Please check if I understand you correctly then this code snippet can help to you solve your problem. I have tested it for your specified problem only. if there are other testcases for which you want to run this, you can tell me to adjust the code.

$a1 = array(
    'a1' => array('a_name' => 'aaa', 'a_value' => 'aaaaa'),
    'b1' => array('b_name' => 'bbb', 'b_value' => 'bbbbbb'),
    'c1' => array('c_name' => 'ccc', 'c_value' => 'cccccc')
);

$a2 = array(
    'b1' => array('b_name' => 'zzzzz'),
);

$result = check_diff_multi($a1, $a2);
print '<pre>';
print_r($result);
print '</pre>';


function check_diff_multi($array1, $array2){
    $result = array();
    foreach($array1 as $key => $val) {
         if(isset($array2[$key])){
           if(is_array($val) && $array2[$key]){
               $result[$key] = check_diff_multi($val, $array2[$key]);
           }
       } else {
           $result[$key] = $val;
       }
    }

    return $result;
}

EDIT: added tweak to code.

Zaheer Abbass
  • 359
  • 2
  • 4
  • Thank you very much @Zaheer Abbass, I was not expecting any replies as my problem was too specific to me only. This is exactly what I wanted. But when `$a2 = 'zzzzz'` I want the result to be `$a1 = array('a1' => array('a_name' => 'aaa', 'a_value' => 'aaaaa'), 'c1' => array('c_name' => 'ccc', 'c_value' => 'cccccc') );` Since the arrays in my case are of many levels. I tried to tweak around but I am just not able to get the result i wanted. Hope you get my problem. Thank you once again for all the helps. I really appreciate it. – kcssm Sep 04 '12 at 05:07
  • @kcssm please edit your question and add your use case in proper formatting so that i can understand it properly. Thanks. – Zaheer Abbass Sep 04 '12 at 07:35
  • Thats right. I added a better working function (see my answer above) – bernhardh Jun 07 '17 at 09:20
  • thiw work only in one direction, i.e. if the array1 is "bigger" than the other? – gdm Mar 07 '18 at 09:18
13

this solution ah been very helpful to me I hope can help them in something, no matter what the array are in disarray.

function your_array_diff($arraya, $arrayb) {

    foreach ($arraya as $keya => $valuea) {
        if (in_array($valuea, $arrayb)) {
            unset($arraya[$keya]);
        }
    }
    return $arraya;
}

$a1 = Array
    (
    "0" => Array
        (
        "Empresa" => "TMC01",
        "Paga" => "13/01/2015",
        "ID" => "M2",
        "Valor" => "200",
        "Nombre" => "BONI"
    ),

    "1" => Array
        (
        "Empresa" => "TMC01",
        "Paga" => "13/01/2015",
        "ID" => "M1",
        "Valor" => "100",
        "Nombre" => "SUELDO"
    )
);

$b1 = Array
    (
    "0" => Array
        (
        "Empresa" => "TMC01",
        "Paga" => "13/01/2015",
        "ID" => "M1",
        "Valor" => "100",
        "Nombre" => "SUELDO"
    ),
    "1" => Array
        (
        "Empresa" => "TMC01",
        "Paga" => "13/01/2015",
        "ID" => "M2",
        "Valor" => "200",
        "Nombre" => "BONI"
    )
);

$resultado = your_array_diff($a1, $b1);

echo "<pre>";
echo print_r($resultado);
echo "</pre>";
Jonny Alexander
  • 189
  • 2
  • 5
11

There are a lot of cases, where original answers will not work properly, so I wrote a better solution. One of the problems was, that if you deleted a property in array 2, the other functions didn't recognized it.

function check_diff_multi($array1, $array2){
    $result = array();

    foreach($array1 as $key => $val) {
        if(is_array($val) && isset($array2[$key])) {
            $tmp = check_diff_multi($val, $array2[$key]);
            if($tmp) {
                $result[$key] = $tmp;
            }
        }
        elseif(!isset($array2[$key])) {
            $result[$key] = null;
        }
        elseif($val !== $array2[$key]) {
            $result[$key] = $array2[$key];
        }

        if(isset($array2[$key])) {
            unset($array2[$key]);
        }
    }

    $result = array_merge($result, $array2);

    return $result;
}

I have also added test cases to check result:

As you can see, my fuctions delivers better results.

bernhardh
  • 3,137
  • 10
  • 42
  • 77
4
$out = array_diff_assoc_recursive($array1, $array2);

The solution requires recursing values of array which may themselves be arrays.

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)
        {
            $difference[$key] = $value;
        }
    }
    return !isset($difference) ? 0 : $difference;
}
Faiz Mohamed Haneef
  • 3,418
  • 4
  • 31
  • 41
3

Almost a copy of @bernhardh's answer but posting here because my edit was rejected. Uses + instead of array_merge as array_merge will reindex array causing issues with indexed arrays.

/**
 * Given 2 arrays see what has changed when comparing defaults to the new values.
 *
 * @param array $defaults
 *   Array of default values.
  * @param mixed $new_values
 *   Array of new values.
 *
 * @return array
 *   Nested array strucutre; only the diff.
 */
function array_diff_multi(array $defaults, $new_values) {
  $result = array();

  foreach ($defaults as $key => $val) {
    if (is_array($val) && isset($new_values[$key])) {
      $tmp = array_diff_multi($val, $new_values[$key]);
      if ($tmp) {
        $result[$key] = $tmp;
      }
    }
    elseif (!isset($new_values[$key])) {
      $result[$key] = NULL;
    }
    elseif ($val != $new_values[$key]) {
      $result[$key] = $new_values[$key];
    }
    if (isset($new_values[$key])) {
      unset($new_values[$key]);
    }
  }

  $result = $result + $new_values;
  return $result;
}
mikeytown2
  • 1,744
  • 24
  • 37
2

I know this thread is kind of old, however I ran into a few problems with the original solution. So here is my solution of the problem.

private function array_diff_recursive($array1, $array2){
    $result = [];
    foreach($array1 as $key => $val) {
        if(array_key_exists($key, $array2)){
            if(is_array($val) || is_array($array2[$key])) {
                if (false === is_array($val) || false === is_array($array2[$key])) {
                    $result[$key] = $val;
                } else {
                    $result[$key] = $this->array_diff_recursive($val, $array2[$key]);
                    if (sizeof($result[$key]) === 0) {
                        unset($result[$key]);
                    }
                }
            }
        } else {
            $result[$key] = $val;
        }
    }
    return $result;
}

Problems Encountered / Fixed

  1. Result populates with keys that have no difference
  2. If one value is an array and the other is not, it doesn't consider it a difference
Jonathan
  • 2,778
  • 13
  • 23
1

Try the function:

<?php
$input = ['blue'  => 1, 'white' => ['purple' => 4, 'green' => 3], 'red' => 2];
$filter = ['blue' => 6, 'white' => ['yellow' => 7, 'green' => 5], 'red' => 2];

/**
 * @param array $input
 * @param array $filter
 * @return array
 */
function multidimensionalArrayDiffKey(array $input, array $filter)
{
    if ($diff = array_diff_key($input, $filter)){
        return $diff;
    }else{
        foreach($input as $key => $value){
            if(is_array($value) && $diff = multidimensionalArrayDiffKey($value, $filter[$key])){
                return [$key => $diff];
            }
        }
    }
    return [];
}
print_r(multidimensionalArrayDiffKey($input, $filter));

Result:

Array
(
    [white] => Array
        (
            [purple] => 4
        )

)
Lebnik
  • 628
  • 8
  • 11
1

A better function that works just like the original array_diff.
Compares array1 against one or more other arrays and returns the values in array1 that are not present in any of the other arrays recursively.

    <?php

    function md_array_diff(array $array1, array $array2, array $_ = null) {
        $diff = [];
        $args = array_slice(func_get_args(), 1);

        foreach ($array1 as $key => $value) {
            foreach ($args as $item) {
                if (is_array($item)) {
                    if (array_key_exists($key, $item)) {
                        if (is_array($value) && is_array($item[$key])) {
                            $tmpDiff = md_array_diff($value, $item[$key]);

                            if (!empty($tmpDiff)) {
                                foreach ($tmpDiff as $tmpKey => $tmpValue) {
                                    if (isset($item[$key][$tmpKey])) {
                                        if (is_array($value[$tmpKey]) && is_array($item[$key][$tmpKey])) {
                                            $newDiff = array_diff($value[$tmpKey], $item[$key][$tmpKey]);
                                        } else if ($value[$tmpKey] !== $item[$key][$tmpKey]) {
                                            $newDiff = $value[$tmpKey];
                                        }

                                        if (isset($newDiff)) {
                                            $diff[$key][$tmpKey] = $newDiff;
                                        }
                                    } else {
                                        $diff[$key][$tmpKey] = $tmpDiff;
                                    }
                                }
                            }
                        } else if ($value !== $item[$key]) {
                            $diff[$key] = $value;

                        }
                    } else {
                        $diff[$key] = $value;
                    }
                }
            }
        }

        return $diff;
    }

    $arr1 = [
      "A" => [
        "A1" => ['A1-0', 'A1-1', 'A1-2', 'A1-3'],
        "A2" => ['A2-0', 'A2-1', 'A2-2', 'A2-3'],
        "A3" => ['A3-0', 'A3-1', 'A3-2', 'A3-3']
      ],
      "B" => [
        "B1" => ['B1-0', 'B1-1', 'B1-2', 'B1-3'],
        "B2" => ['B2-0', 'B2-1', 'B2-2', 'B2-3'],
        "B3" => ['B3-0', 'B3-1', 'B3-2', 'B3-3']
      ],
      'C' => 123
    ];

    $arr2 = [
      "A" => [
        "A1" => ['A1-1', 'A1-2', 'A1-3'],
        "A2" => ['A2-0', 'A2-1', 'A2-2', 'A2-3'],
        "A3" => ['A3-0', 'A3-1', 'A3-2']
      ],
      "B" => [
        "B1" => ['B1-0', 'B1-2', 'B1-3'],
        "B2" => ['B2-0', 'B2-1', 'B2-2', 'B2-3'],
        "B3" => ['B3-0', 'B3-1', 'B3-3']
      ]
    ];

    $arr3 = [
      "A" => [
        "A1" => ['A1-0', 'A1-1', 'A1-2', 'A1-3'],
        "A2" => ['A2-0', 'A2-1', 'A2-2', 'A2-3'],
        "A3" => ['A3-0', 'A3-1', 'A3-2']
      ],
      "B" => [
        "B1" => ['B1-0', 'B1-2', 'B1-3'],
        "B2" => ['B2-0', 'B2-1', 'B2-2', 'B2-3'],
        "B3" => ['B3-0', 'B3-1', 'B3-3']
      ]
    ];

    $diff = md_array_diff($arr1, $arr2, $arr3);

    ?>
    Will Output:
    array (size=3)
      'A' =>
          array (size=2)
            'A1' =>
              array (size=1)
                0 => string 'A1-0' (length=4)
            'A3' =>
              array (size=1)
                3 => string 'A3-3' (length=4)
      'B' =>
          array (size=2)
            'B1' =>
              array (size=1)
                1 => string 'B1-1' (length=4)
            'B3' =>
              array (size=1)
                2 => string 'B3-2' (length=4)
      'C' => int 123
Dharman
  • 30,962
  • 25
  • 85
  • 135
1

Better to check the if an entire array is available in the second array

        function array_diff_assoc_recursive($arraya, $arrayb) {
            foreach ($arraya as $keya => $valuea) {
                if (in_array($valuea, $arrayb)) {
                    unset($arraya[$keya]);
                }
            }
            return $arraya;
        }

This could be the as simple , quick and shortest way to identify the difference!

Punit Gajjar
  • 4,937
  • 7
  • 35
  • 70
0

One small tweak to @Zaheer Abbass solution, I got the result I wanted. Thank you very much Zaheer. Here is the final code that i used.

function check_diff_multi($array1, $array2){
    $result = array();
    foreach($array1 as $key => $val) {
        if(isset($array2[$key])){
           if(is_array($val)  && is_array($array2[$key])){
                $result[$key] = check_diff_multi($val, $array2[$key]);
            }
        } else {
            $result[$key] = $val;
        }
    }

    return $result;
} 
kcssm
  • 1,727
  • 3
  • 16
  • 19
0

So if you have arrays with empty values or with empty arrays.

private function check_diff_multi($array1, $array2){
    $result = array();
    foreach($array1 as $key => $val) {
        if(array_key_exists($key,$array2)){
            if(is_array($val) && is_array($array2[$key]) && !empty($val)){
                $result[$key] = $this->check_diff_multi($val, $array2[$key]);
            }
        } else {
            $result[$key] = $val;
        }
    }
    return $result;
}
fdrv
  • 852
  • 1
  • 11
  • 21
0

It appears that you need, at most, one foreach loop to access the first level keys in your filter array, then depending on whether there is a second level to your filtering array, you either make another round of comparisons with array_diff_key() or directly unset() the qualifying data from the first level.

Code: (Demo)

$a1 = array(
    'a1' => array('a_name' => 'aaa', 'a_value' => 'aaaaa'),
    'b1' => array('b_name' => 'bbb', 'b_value' => 'bbbbbb'),
    'c1' => array('c_name' => 'ccc', 'c_value' => 'cccccc')
);

function twoLevelFilter($master, $filter) {
    foreach ($filter as $key => $value) {
        if (isset($master[$key])) {
            if (is_iterable($value)) {
                $master[$key] = array_diff_key($master[$key], $value);
            } else {
                unset($master[$key]);
            }
        }
    }
    return $master;
}

var_export(twoLevelFilter($a1, ['b1' => ['b_name' => 'zzzzz']]));
echo "\n---\n";
var_export(twoLevelFilter($a1, ['b1' => 'zzzzz']));

Output:

array (
  'a1' => 
  array (
    'a_name' => 'aaa',
    'a_value' => 'aaaaa',
  ),
  'b1' => 
  array (
    'b_value' => 'bbbbbb',
  ),
  'c1' => 
  array (
    'c_name' => 'ccc',
    'c_value' => 'cccccc',
  ),
)
---
array (
  'a1' => 
  array (
    'a_name' => 'aaa',
    'a_value' => 'aaaaa',
  ),
  'c1' => 
  array (
    'c_name' => 'ccc',
    'c_value' => 'cccccc',
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
0

function sort($value){
    foreach($value as $i =>  $v){
        if(is_array($v))
            $value[$i] = sort($v);
    }
    
    ksort($value);
    return $value;
}

function isDifferent(array $array1, array $array2){
    return json_encode(sort($array1), true) != json_encode(sort($array2), true);
}

$arr1 = ["a" => "A", "b" => "B", "c" => ["d" => "D"]];
$arr2 = ["a" => "A", "b" => "B", "c" => ["x" => "X"]];

if(isDifferent($arr1, $arr2)){
    echo "They are different";
}else{
    echo "Both arrays are equal";
}
  • Hi, that is a lot of text. It would be very helpful if you could comment to let us know know you answer differs from the 13 answers above yours. Thanks! – Simas Joneliunas Mar 13 '22 at 23:57
  • @SimasJoneliunas I am not here to compete. My solution works and that's what matters. – Bruno Santos Mar 15 '22 at 00:37
  • its not about the competition, its more about telling others WHY its working and HOW its different from the previous answers. Imagine that I am a new person coming here with the same problem, can you tell me how is your solution different from others? A code blob without any comments does not tell much if anything... – Simas Joneliunas Mar 15 '22 at 07:25
-3

print_r(array_diff_key($array1,$array2));