array_udiff seems not work

你离开我真会死。 提交于 2019-12-23 02:32:09

问题


I'm trying to compare two array with array_udiff, but it's very weired. it seems array_udiff not get the right answer. Here is the live demo. The result should be an empty array, but leave one element unfiltered out.

<?php

$string = '{
  "sakiniai": [

      {
        "Faktas": "A",
        "value": "true"
      },
      {
        "Faktas": "B",
        "value": "true"
      },
      {
        "Faktas": "A",
        "value": "false"
      }
  ]
}';

$sakiniais = json_decode($string, true)['sakiniai'];


$v = $sakiniais[0];
$arr[] = $v;
$v['value'] = $v['value'] == "true" ? "false" : "true";
$arr[] = $v;
var_dump($arr);
var_dump($sakiniais);


print_r(array_udiff($arr, $sakiniais, function($a, $b){
/*
var_dump($a);
var_dump($b);
var_dump($a == $b);
echo "\n\n\n";
*/
return $a == $b ? 0 : -1;}
));

the output

    array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}
array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}
Array
(
    [1] => Array
        (
            [Faktas] => A
            [value] => false
        )

)

回答1:


The problem is that array_udiff is not performing the comparison between all values, and this seems to be caused by your compare function.

array_udiff() expects that the callable function is a real compare function, but you are returning always 0 and -1, but never 1.

Before doing its job, array_udiff() tries to order both arrays and remove duplicates too. If it can't rely on your comparison function, it can't perform all the needed comparison and some values are "jumped".

Look at all comments in the documentation expecially napcoder comment

Note that the compare function is used also internally, to order the arrays and choose which element compare against in the next round.

If your compare function is not really comparing (ie. returns 0 if elements are equals, 1 otherwise), you will receive an unexpected result.

This is demonstrated looking at your arrays

$arr

array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

and $sakiniais

array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

You should expect all the combinations between the two arrays to be tested, but the tested combinations (below) doesn't include A-False vs. A-False

array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
bool(true)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
bool(false)

In the correct answer at this post there are some other useful insights on how array_udiff works

You can change your return statement like this

if ($a < $b) {
    return -1;
} elseif ($a > $b) {
    return 1;
} else {
    return 0;
}

(if you are wondering how two arrays can be compared for less/greater, have a look at this link, in the section "Comparison with Various Types" and the "Example #2 Transcription of standard array comparison" example)




回答2:


Nothing strange, everything works as expected. Take a look at arrays comparing:

$arraysAreEqual = ($a == $b); // TRUE if $a and $b have the same key/value pairs.
$arraysAreEqual = ($a === $b); // TRUE if $a and $b have the same key/value pairs in the same order and of the same types.

so, $arr[0] == $sakiniai[0] is true, but $arr[1] == $sakiniai[2] is false and the output is $arr[1]

$arr

array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

$sakiniai

array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

result

Array
(
    [1] => Array
        (
            [Faktas] => A
            [value] => false
        )

)


来源:https://stackoverflow.com/questions/43998995/array-udiff-seems-not-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!