【问题标题】:comparing arrays in PHP - interesting behaviour比较 PHP 中的数组 - 有趣的行为
【发布时间】:2011-06-25 20:34:00
【问题描述】:

第一个例子:

$x = array("a" => 1, "b" => 2); 
$y = array("b" => 1, "a" => 2);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);

结果:$xLessY = true,$xGreaterY = true

第二个例子:

$x = array("a" => 2, "b" => 1); 
$y = array("b" => 2, "a" => 1);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);

结果:$xLessY = false,$xGreaterY = false

根据http://docs.php.net/manual/en/language.operators.comparison.php 上的文档:

如果操作数 1 中的键在 操作数 2 那么数组是 无法比较,否则 - 比较 按价值计算

在我们的例子中,数组 $x 中的每个键都存在于数组 $y 中,因此 $x 和 $y 是可比较的。 另请参阅文档中的示例:

// Arrays are compared like this with standard comparison operators
function standard_array_compare($op1, $op2)
{
    if (count($op1) < count($op2)) {
        return -1; // $op1 < $op2
    } elseif (count($op1) > count($op2)) {
        return 1; // $op1 > $op2
    }
    foreach ($op1 as $key => $val) {
        if (!array_key_exists($key, $op2)) {
            return null; // uncomparable
        } elseif ($val < $op2[$key]) {
            return -1;
        } elseif ($val > $op2[$key]) {
            return 1;
        }
    }
    return 0; // $op1 == $op2
}

这种行为真的很奇怪:$x 小于 $y,同时 $x 大于 $y(第一个例子),两个数组是可比的。

我认为这是因为 php 总是从符号 ' $y) 它将 $y 作为操作数 1。虽然我在文档中没有找到任何关于此行为的信息。
您对此有何看法?

【问题讨论】:

  • 我怀疑你可能是正确的关于&lt; 的尖端的值如何被用作第一个操作数。当然,看PHP源码就可以肯定找到答案了……

标签: php arrays compare


【解决方案1】:

你的假设是正确的。 &gt; 操作符被解析为

|   expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }

这基本上说,X &gt; Y 等价于not X &lt; Y,当比较不可交换时当然是错误的。考虑在 bugs.php.net 上报告。

【讨论】:

  • 可交换? X &gt; Y 可交换意味着X &gt; Y 等价于Y &gt; X。另外,您说“比较(顺便说一句)不是可交换的”意味着X &gt; Y 不等于not X &lt; Y。从对立中得出X &gt; Y 等价于not X &lt; Y 意味着比较是可交换的,这显然是一个无意义的陈述。另外,该错误不存在,因为手册指出这两个操作数确实具有可比性,因此人们会期望反对称,因为$x &gt; $y$y &gt; $x 对于$x != $y 是正确的,所以没有验证。
  • 我同意没有明智的方法来对关联数组进行排序,但这并不意味着设置任意顺序没有用——例如,许多算法依赖于被排序的数据。然而,目前的情况是,不仅在数组的宇宙中没有完全的顺序,而且手册声明有明确定义顺序的数组实际上在&lt;&gt;.
【解决方案2】:

我不会说错误在于 $x &gt; $y 被替换为 $y &lt; $x

当然,如果您实现$x &gt; $y 的方式是在传递给比较函数时参数不交换位置,您将解决这个特殊问题。但你会得到另一个回报。

现在你有:

$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($y, $x) == -1

因为总是先比较第一个参数的第一个键,所以如果reset($x) &lt; $y[key($x)]reset($y) &lt; $x[key($y)] 两个条件都为真。

但是考虑另一种实现,它可以解决这个问题:

$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($x, $y) == +1

现在&lt;&gt; 在操作数的顺序固定时是一致的,但是当我们交换操作数时我们现在会出现奇怪的行为,因为我们仍然可以有cmp($x, $y) == -1cmp($y, $x) == -1,这意味着@ 987654332@ 和 $y &lt; $x 都是真的。

总之,唯一的解决方案是修复比较函数,使其行为是反对称的,即,至少在一组声称可比较的元素中,cmp($x, $y) == - cmp($y, $x)

【讨论】:

  • 我认为这种行为$x &lt; $y == -1$y &lt; $x == -1 在无序数组的情况下更容易理解。而且这更符合文档。
  • 也许这不是一个错误,但他们应该记录下来
【解决方案3】:

我可能错了,但我认为你不能这样比较数组。我一直认为可以检查相等或不等,但不能用 比较数量。

man page on array operators 似乎证实了这一点。

【讨论】:

  • another man page。请参阅表“与各种类型的比较”和下面的文本:“成员较少的数组更小,如果在操作数 2 中找不到来自操作数 1 的键,则数组不可比较,否则 - 按值比较值(参见以下示例)” .还有我写的例子(standard_array_compare函数)
猜你喜欢
  • 1970-01-01
  • 2011-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
相关资源
最近更新 更多