21

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
     )

)
7
  • In your expected output you are not compare, but replace b1. What do you really want? Commented Sep 3, 2012 at 10:30
  • I want the difference of the two array. The expected output is the difference of the two array, not replace. Commented Sep 3, 2012 at 10:33
  • 3
    If from 14 answers none solved you problems, you might want to reconsider your style of writing a question! Commented Sep 3, 2012 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. Commented Sep 3, 2012 at 10:33
  • If you'd take a look at PHP DOCS (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. Commented Sep 3, 2012 at 10:35

14 Answers 14

21

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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 please edit your question and add your use case in proper formatting so that i can understand it properly. Thanks.
Thats right. I added a better working function (see my answer above)
thiw work only in one direction, i.e. if the array1 is "bigger" than the other?
14

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

Comments

12

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.

2 Comments

I don't want to detect a difference when one result is '' and another is NULL
this one does not work with simple lists array(1,5,4) vs array(1,4,5)
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;
}

Comments

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

Comments

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

Comments

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
        )

)

Comments

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

Comments

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!

Comments

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

Comments

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

Comments

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',
  ),
)

Comments

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";
}

3 Comments

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!
@SimasJoneliunas I am not here to compete. My solution works and that's what matters.
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...
-2

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

1 Comment

array_diff_key is a built in function to find the differences in key of two arrays

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.