array_diff_uassoc的行为不清楚

时间:2012-02-27 00:22:59

标签: php arrays array-difference

首先,我需要提一下,我深入研究手册和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)

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

3 个答案:

答案 0 :(得分:0)

来自op's comment

  

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

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

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

,否则

The documentation声明:

  

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

据我了解,这意味着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这是因为它超出了答案的范围。

答案 1 :(得分:0)

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

  

返回一个数组,其中包含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 =&gt; d与关联级别$ 2 = 0 =&gt; d不匹配$ one hot =&gt; d返回。

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

这有助于在类型不明确的情况下'0'=&gt; d和0 =&gt; d可能看起来相似但直到您在代码中这样说。

幸运的是,类型提示正在PHP7中,以摆脱这种奇怪的构造和不清楚的文档。

我在评论中添加此内容,因为它与您了解哪种php结构最适合您的情况有关。我的评论:

  

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

答案 2 :(得分:0)

这确实有点吸引人。我在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的任何经验,现在已经很晚了,我已经厌倦了尝试去理解它。我想首先进行关键比较,因为比较值可能更有效,但这只是猜测。无论如何,他们可能就像他们那样做的原因有很好的理由。

所有这些只是一个很长的介绍,为什么你想在echo功能首先放入compare array_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

这样你可以依赖行为不改变,你可以完全控制内部工作......