views:

998

answers:

4

It seems that every PHP function I read about for comparing arrays (array_diff(), array_intersect(), etc) compares for the existence of array elements.

Given two multidimensional arrays with identical structure, how would you list the differences in values?

Example

Array 1

[User1] => Array ([public] => 1
                [private] => 1
                [secret] => 1
               ) 
[User2] => Array ([public] => 1
                [private] => 0
                [secret] => 0
               )

Array 2

[User1] => Array ([public] => 1
                [private] => 0
                [secret] => 1
               ) 
[User2] => Array ([public] => 1
                [private] => 0
                [secret] => 0
               )

Difference

[User1] => Array ([public] => 1
                [private] => 0 //this value is different
                [secret] => 1
               )

So my result would be - "Of all the users, User1 has changed, and the difference is that private is 0 instead of 1."

+3  A: 

One way is to write a function to do something similar to this..

function compareArray ($array1, $array2)
{
  foreach ($array1 as $key => $value)
  {
    if ($array2[$key] != $value)
    {
      return false;
    }
  }

  return true;
}

You could easily augment that function to return an array of differences in the two..

Edit - Here's a refined version that more closely resembles what you're looking for:

function compareArray ($array1, $array2)
{
  var $differences;

  foreach ($array1 as $key => $value)
  {
    if ($array2[$key] != $value)
    {
      $differences[$key][1] = $value;
      $differences[$key][2] = $array2[$key];
    }
  }

  if (sizeof($differences) > 0)
  {
    return $differences;
  }
  else
  { 
    return true;
  }
}
Ian P
He asked for a multidimensional array checking. Need to do a is_Array followed by a comparyArray recursion.
Byron Whitlock
Above Code doesnt work in cases the other Array is longer and contains diffrent keys. you need to first check you would do is for array length if you want to make sure they are identical only then continue to checkign itmes.
I'm sorry...does `var` exist in php?
Mussnoon
Yes -- var exists, but I used it out of scope. You use it at class level declarations, rather than method level.
Ian P
A: 

Try this function:

function arrayDiff($array1, $array2)
{
    if (!is_array($array1) || !is_array($array2)) {
        return false;
    }
    foreach ($array1 as $key => $val) {
        if (array_key_exists($key, $array2) && gettype($val) != "array" && $val === $array2[$key]) {
            unset($array1[$key]);
            continue;
        }
        if (is_array($val)) {
            $val = diff($val, $array2[$key]);
            if ($val !== false) {
                $array1[$key] = $val;
            }
        }
    }
    return $array1;
}

$array1 = array(
    array(
        array('foo', 'bar', 'baz'),
        0
    )
);
$array2 = array(
    array(
        array('foo', 'bar')
    )
);
var_dump(diff($array1, $array2));
Gumbo
A: 

If you're looking for differences in the values, how about array_diff_assoc. The php manual says it "returns an array containing all the values from array1 that are not present in any of the other arrays" and gives the following example:

In this example you see the "a" => "green" pair is present in both arrays and thus it is not in the ouput from the function. Unlike this, the pair 0 => "red" is in the ouput because in the second argument "red" has key which is 1

<?php
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red");
$array2 = array("a" => "green", "yellow", "red");
$result = array_diff_assoc($array1, $array2);
print_r($result);
?>

The above example will output:

Array
(
    [b] => brown
    [c] => blue
    [0] => red
)

Is this what you're looking for?

notruthless
Not exactly. This will say "blue is in array1 but not array2." I want "the following items are blue in array1 but red in array2." I will have identically-structured arrays and the only possible values are 0 and 1 - I want to see which nodes differ.
Nathan Long
Right. Looks like you need to loop through manually if you need to know exactly which user changed.
notruthless
OK, I left another idea in another answer. I think it's close, at least.
notruthless
+1  A: 

I think this does what you're looking for.

Using your sample data, doing a loop on the outer arrays, then using array_diff_assoc on the users each time through. (Note, this assumes that when there's a difference, array_diff_assoc returns the value from the second array passed in, which it seems to do).

<?php
$user1 = array("public" => 1, "private" => 1, "secret" => 1);
$user2 = array("public" => 1, "private" =>1, "secret" => 1);
$array1 = array ("user 1"=>$user1, "user 2"=>$user2);

$user1 = array("public" => 1, "private" => 0, "secret" => 1);
$user2 = array("public" => 1, "private" => 1, "secret" => 1);
$array2 = array("user 1"=>$user1, "user 2"=>$user2);

$results = array();  
foreach ( $array1 as $user => $value )
{
    $diff = array_diff_assoc( $array1[$user], $array2[$user] );
    if ($diff) {
     array_push($results,array($user=>$diff)); 
     }
}


print_r($results);


?>

It returns:

Array
(
    [0] => Array
        (
            [user 1] => Array
                (
                    [private] => 1
                )
        )    
)
notruthless