array_diff_uassoc 的行为不清楚

Posted

技术标签:

【中文标题】array_diff_uassoc 的行为不清楚【英文标题】:Behavior of array_diff_uassoc not clear 【发布时间】:2012-03-16 13:12:13 【问题描述】:

首先我需要提到的是,我深入研究了手册和 php 文档,但没有找到答案。这是我使用的代码:

class chomik 

    public $state = 'normal';
    public $name = 'no name';

    public function __construct($name) 
        $this->name = $name;
    

    public function __toString() 
        return $this->name . " - " . $this->state;
    


function compare($a, $b) 
    echo("$a : $b<br/>");
    if($a != $b) 
        return 0;
    
    else return 1;


$chomik = new chomik('a');
$a = array(5, $chomik, $chomik, $chomik);
$b = array($chomik, 'b', 'c', 'd');
array_diff_uassoc($a, $b, 'compare');

我的想法是,array_diff_uassoc 将比较这两个数组的所有值,如果值存在,则运行键比较。这段代码的输出是:

1 : 0
3 : 1
2 : 1
3 : 2
1 : 0
3 : 1
2 : 1
3 : 2
3 : 3
3 : 2
2 : 3
1 : 3
0 : 3

那么首先为什么有些对(1 : 0 或 3 : 1)是重复的?这是否意味着函数忘记了它已经比较了这些项目?我认为它会比较所有相等的值对,但我没有在输出中看到它。我错过了什么吗?

所以问题是:这个函数在比较顺序方面的确切行为是什么,为什么我看到这个重复? (我的 PHP 版本,如果有帮助的话:PHP 版本 5.3.6-13ubuntu3.6)

我真的很困惑,等待一些好的解释......

【问题讨论】:

您可能应该在比较函数中使用严格比较!== 而不是 ==。 在这种情况下,说实话,比较本身并不是什么大问题。我想知道为什么echo 在比较时会打印这样的结果。 echo 是在比较之前触发的,所以我认为它是否严格并不重要。 编写这段代码我想要实现的是:我只想要那些不在第二个数组($a[0])中的元素,如果它们在第二个数组中,我想要这些元素具有相同的键(索引)...所以当然函数应该只返回 $a[0] 我也很困惑是比较数组索引还是其他东西。我认为它实际上并没有比较数组索引。即使我们使用 array_diff_unassoc 进行了 3 个数组比较,传递给回调函数的参数也只有 2 个。 我有两个数组:$array1 = array("a" =&gt; "a", "b" =&gt; "b", "c" =&gt; "c", "d" =&gt; "d");$array2 = array("x" =&gt; "x","y" =&gt; "y","z" =&gt; "z");,它给了我这对:b - ab - cd - bc - bd - cy - x98765343@332@98765343@33 a - ya - zb - xb - yb - zc - xc - yc - zd - xd - xd - yd - z我不知道为什么这个函数比较数组。跨度> 【参考方案1】:

我认为你错过了返回值部分。

返回一个数组,其中包含 array1 中不存在于任何其他数组中的所有条目。

数组键用于比较。

文本中缺少的是,比较只是关联进行的。这意味着任何自动声明或用户定义的数字键都被键入为字符串而不是整数。

所以

$one = array(a,b,c,'hot'=>d); // d has no match and  will be returned as array and go to the function alone
$two = array(a,b,c,d,e,f); //

因为 $one hot=>d 与关联级别上的 $two 0=>d 不匹配,所以返回 $one hot=>d。

由于字符串和整数数据类型比较的 PHP 怪癖,用户定义的函数可用于通过使用更强大的比较操作(如 ===)来增强比较。

这有助于在类型不明确的情况下 '0'=>d 和 0=>d 可能看起来相似,但除非你在代码中这样说。

幸运的是,PHP7 中的类型提示让我们摆脱了这种奇怪的结构和不清楚的文档。

我从我的评论中添加了这一点,因为它与您对哪种 php 构造最适合您的情况的理解有关。我的评论:

我不太确定,因为 if($a != $b) 在他们的代码中是 问题。因为他们在应该使用的时候错误地使用了相等 使用相同的运算符!==。他们正在使用数字键 为关联键设计的构造。他们可能也是 不知道 array_udiff 与所涉及的数据更匹配

【讨论】:

很明显 op 非常清楚你在说什么。 我不太确定,因为 if($a != $b) 在他们的代码中是一个问题。因为当他们应该使用相同的运算符时,他们错误地使用了相等性。他们在为关联键设计的结构中使用数字键。他们可能也不知道 array_udiff 更适合所涉及的数据【参考方案2】:

这确实有点有趣。我在 github 上查找了 PHP 的最新源代码(你可能知道它是用 C++ 编写的)并试图理解它。 (https://github.com/php/php-src/blob/master/ext/standard/array.c)

快速搜索显示,有问题的函数是在第 4308 行声明的

PHP_FUNCTION(array_diff_uassoc)

    php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);

这表明实际工作是由php_array_diff 函数完成的,可以在第 3938 行的同一个文件中找到。在这里粘贴它有点长,确切地说是 265 行,但你可以看看如果你愿意,可以。

这就是我放弃的地方。我在 C 方面没有任何经验,而且为时已晚,我已经厌倦了尝试理解它。我想首先进行键比较,因为它可能比比较值更有效,但这只是一个猜测。无论如何,他们这样做可能有一个很好的理由。

这只是一个很长的介绍,你为什么要首先在你的compare 函数中放置一个echoarray_diff_uassoc 的目标是函数的输出。您不应该依赖解析器如何处理它。如果他们明天决定将该 C 函数的内部工作方式更改为 ie。先做数值比较,你会得到完全不同的结果。

也许你可以使用这个用php编写的替换函数:http://pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

这样您可以依靠行为不会改变,并且您可以完全控制内部运作...

【讨论】:

这是您的 github 链接的第 3631 行: else if (behavior &amp; INTERSECT_ASSOC &amp;&amp; key_compare_type == INTERSECT_COMP_KEY_USER) 。第 3321 行是空行。很明显,回声不是为了功能而是为了测试,它确实显示出奇怪的结果。 @FélixGagnon-Grenier 对不起,我把行号弄乱了(我实际上是从 php.net 下载源代码的,后来才发现源代码也在 Github 上。我以为这样会更容易链接到那里,但忘记检查行号。虽然 Ctrl/Cmd + F 会带你到那里)现在更新,但由于链接指向当前主节点,因此将来可能会再次更改。 我的回答是,您应该将该功能视为一个黑匣子,而不是依赖于它的内部运作。一切都与 API 和输出有关,现在如何函数获得该结果,因为将来可能会改变。【参考方案3】:

来自op'scomment那个

我只想要那些不在第二个数组 ($a[0]) 中的元素

你不能用array_diff($a, $b);吗?它返回

array(1) 
  [0]=>
  int(5)


否则,

The documentation 声明:

如果第一个参数被认为分别小于、等于或大于第二个参数,则比较函数必须返回一个小于、等于或大于零的整数。 p>

据我了解,这意味着compare() 函数应该更像这样:

function compare($a, $b) 
    echo("$a : $b<br/>");
    if($a === $b) return 0;
    else if ($a > $b) return 1;
    else return -1;

然而,即使有了这个修正,它的比较结果也很奇怪:

1 : 0 1:2 3:1 2:1 3 : 2 1 : 0 1:2 3:1 2:1 3 : 2 0 : 0 1 : 0 1:1 2 : 0 2:1 2:2 3 : 0 3:1 3 : 2 3 : 3

我问了another question 这个问题,因为它超出了答案的范围。

【讨论】:

以上是关于array_diff_uassoc 的行为不清楚的主要内容,如果未能解决你的问题,请参考以下文章

EXTJS 更改 GridPanel 行选择的默认行为

不清楚调整 UIWebView 的大小行为

NOT IN with Nulls - 不清楚的行为[重复]

XCTest 的行为在 assertTrue 上不清楚失败

多线程应用程序的行为不清楚:无法退出线程

事务,这次还有不清楚的吗,一次实战坑