0

I have two arrays I want to compare:

animals1:

array(4) {
  ["1234"]=>
  array(5) {
    ["animal"]=>
    string(19) "cat"
    ["name"]=>
    string(12) "fred"
    ["food"]=>
    string(32) "milk"
  }
  ["5678"]=>
  array(5) {
    ["animal"]=>
    string(19) "dog"
    ["name"]=>
    string(12) "sam"
    ["food"]=>
    string(32) "chicken"
  }
  ["shop"]=>
  string(12) "petcenter"
}

animals2:

array(4) {
  ["1234"]=>
  array(5) {
    ["animal"]=>
    string(19) "cat"
    ["name"]=>
    string(12) "tom"
    ["food"]=>
    string(32) "juice"
  }
  ["5678"]=>
  array(5) {
    ["animal"]=>
    string(19) "dog"
    ["name"]=>
    string(12) "sam"
    ["food"]=>
    string(32) "fish"
  }
  ["shop"]=>
  string(12) "petcenter"
}

Here is my code:

foreach ($animals1 as $k1 => $v1) {
   if (array_diff($animals2[$k1], $animals1[$k1])){
      $diff[$k1] = array_diff($animals2[$k1], $animals1[$k1]);
   }
} 
foreach ($animals2 as $k1 => $v1) {
   if (array_diff($animals1[$k1], $animals2[$k1])){
      $diff2[$k1] = array_diff($animals1[$k1], $animals2[$k1]);
   }
}
function result1($item, $key){
   echo $key."1 = ".$item;
   echo "<br>";
}
function result2($item, $key){
   echo $key."2 = ".$item;
   echo "<br>";
}
foreach ($diff as $d => $key){

    foreach ($animals1 as $p => $row) {
            if ($p == $d){
                  echo "Error for animal".$row["animal"];
                  echo "with the name:".$row["name"].".";
            }   
        }   
}
array_walk_recursive($diff, 'result1');
array_walk_recursive($diff2, 'result2');

My result is:

Error for animal cat with name fred.
Error for animal dog with name sam.

name1 = fred
food1 = milk
food1 = chicken

name2 = tom
food2 = juice
food2 = fish

But what I would need is this:

Error for animal cat with name fred.

name1 = fred
name2 = tom

food1 = milk
food2 = juice

Error for animal dog with name sam.

food1 = chicken
food2 = fish

That means, at first I want to display that there is an error for a specific animal with a specific name. After this, I want to display the differences. that means always the value of animal1 and after that the value of animal2. I do not know how to change my code the best way to achieve the result I wish.


This is the output of Standej:

Error for animal cat with name fred.

name1 = fred
food1 = milk
food1 = chicken

name2 = tom
food2 = juice
food2 = fish

Error for animal dog with name sam.

name1 = fred
food1 = milk
food1 = chicken

name2 = tom
food2 = juice
food2 = fish
peace_love
  • 6,229
  • 11
  • 69
  • 157
  • 1
    Possible duplicate of [php two Multidimensional Array difference](http://stackoverflow.com/questions/27856743/php-two-multidimensional-array-difference) – Elias Nicolas Nov 29 '15 at 18:36
  • @Elias Nicolas I need to compare the keys differently – peace_love Nov 29 '15 at 18:50
  • Using `array_diff` for this will lead to strange results if the `name` value of one cat equals the `food` value of the other cat, and vice versa. – trincot Nov 29 '15 at 20:10

2 Answers2

1

Try to reorder your code if you want reordered results

foreach ($animals1 as $k1 => $v1) {
   if (array_diff($animals2[$k1], $animals1[$k1])){
      $diff[$k1] = array_diff($animals2[$k1], $animals1[$k1]);
   }
} 
foreach ($animals2 as $k1 => $v1) {
   if (array_diff($animals1[$k1], $animals2[$k1])){
      $diff2[$k1] = array_diff($animals1[$k1], $animals2[$k1]);
   }
}
function result1($item, $key){
   echo $key."1 = ".$item;
   echo "<br>";
}
function result2($item, $key){
   echo $key."2 = ".$item;
   echo "<br>";
}
foreach ($diff as $d => $key){

    foreach ($animals1 as $p => $row) {
            if ($p == $d){
                  echo "Error for animal".$row["animal"];
                  echo "with the name:".$row["name"].".";
// Put your functions inside loop where you printing errors
                  array_walk_recursive($diff, 'result1');
                  array_walk_recursive($diff2, 'result2');
// End of change
            }   
        }   
}

Hope it will work

Standej
  • 749
  • 1
  • 4
  • 11
  • Thank you, but I do not get the output I needed. I posted the result of your answer in my question. – peace_love Nov 29 '15 at 19:01
  • I have a question. You must use array_walk_recursive or I can try to write you results on different way without use of this function? @Jarla – Standej Nov 29 '15 at 19:14
  • I am happy for every way to the result :) Doesn't need to be array_walk_recursive – peace_love Nov 29 '15 at 19:41
0

The problem with using array_diff is that it only compares values, not the keys, so you could have a failure to detect a difference if the name of one cat is equal to the food of the other, and vice versa.

It would be an improvement to use array_diff_assoc which also compares the keys.

Still, the code would miss some differences, like when the first animal has a missing key, e.g. no food. The $diff array will not have this difference, and since the code iterates over $diff, the corresponding animal will not be included in the output if all the rest is equal.

The original code also assumes that animal and name keys are always there.

Here is some code that should work even if some keys are missing on either side:

function outputDiff($animals1, $animals2) {
    foreach($animals1 as $key => $animal1) {
        // skip animals that only exist in one of the two arrays
        if (!is_array($animal1) || !isset($animals2[$key])) continue;
        $animal2 = $animals2[$key];
        if (!is_array($animal2)) continue;
        // add "animal" and "name" keys to first animal when they are missing
        $animal1 = array_merge(array("animal"=>"(unknown)","name"=>"(unknown)"),
                     $animal1);
        // collect the keys that either animal has:
        $properties = array_unique(array_merge(
                        array_keys($animal1), array_keys($animal2)));
        $equal = true;
        foreach ($properties as $property) {
            // get values from both sides, default to '(unknown)'
            $value1 = isset($animal1[$property]) ? $animal1[$property] : '(unknown)';
            $value2 = isset($animal2[$property]) ? $animal2[$property] : '(unknown)';
            if ($value1 !== $value2) {
                if ($equal) { 
                    // display header
                    echo "<h4>Error for animal {$animal1['animal']}" .
                              "with name {$animal1['name']}</h4>";
                    $equal = false;
                }
                // display detail
                echo "<p>{$property}1 = $value1<br>"; 
                echo "{$property}2 = $value2</p>";
            }
        }   
    }
}

// Set-up test data
$animals1 = array(
  "1234"=>array(
    "animal"=>"cat",
     "name"=>"fred",
    "food"=>"milk"
  ),
  "5678"=>array(
    "animal"=>"dog",
    "name"=>"sam",
    "food"=>"chicken"
  ),
  "8888"=>array(
    "animal"=>"cow",
    "name"=>"freddy",
    "food"=>"grass"
  ),
  "shop"=>"petcenter"
);
$animals2 = array(
  "1234"=>array(
    "animal"=>"cat",
    "name"=>"tom",
    "food"=>"juice"
  ),
  "5678"=>array(
    "animal"=>"dog",
    "name"=>"sam",
    "food"=>"fish"
  ),
  "shop"=>"petcenter"
);

// Perform test
outputDiff($animals1, $animals2);

This code outputs html tags (remove them if they bother you). The output of the above is:

Error for animal cat with name fred

name1 = fred

name2 = tom

food1 = milk

food2 = juice

Error for animal dog with name sam

food1 = chicken

food2 = fish

trincot
  • 317,000
  • 35
  • 244
  • 286