【问题标题】:PHP: How are array items passed to the value compare function when using usort()?PHP:使用 usort() 时如何将数组项传递给值比较函数?
【发布时间】:2015-11-21 23:34:27
【问题描述】:

我试图了解在使用usort() 时如何将数组中的项目传递给我的值比较函数。每次迭代的$x$y 值的打印输出如下:

迭代 1:

// $x
array(2) { ["k1"]=> int(21) ["k2"]=> string(1) "e" }

// $y
array(2) { ["k1"]=> int(920) ["k2"]=> string(1) "z" }

迭代 2:

// $x
array(2) { ["k1"]=> int(842) ["k2"]=> string(1) "t" }

// $y
array(2) { ["k1"]=> int(21) ["k2"]=> string(1) "e" } 

迭代 3:

// $x
array(2) { ["k1"]=> int(920) ["k2"]=> string(1) "z" } 

// $y
array(2) { ["k1"]=> int(21) ["k2"]=> string(1) "e" } 

迭代 4:

// $x
array(2) { ["k1"]=> int(842) ["k2"]=> string(1) "t" } 

// $y
array(2) { ["k1"]=> int(920) ["k2"]=> string(1) "z" } 

我的数据:

$data = array(
    array( 'k1' => 920, 'k2' => 'z' ),
    array( 'k1' => 21, 'k2' => 'e' ),
    array( 'k1' => 842, 'k2' => 't' )
);

我的自定义函数:

function value_compare_func( $x, $y ) {
    if ( $x['k1'] > $y['k1'] ) {
        return true;
    } elseif ( $x['k1'] < $y['k1'] ) {
        return false;
    } else {
        return 0;
    }
}

对数组进行排序:

usort( $data, 'value_compare_function' );

对于第一次迭代,$x['k1']$data[1]['k1']$y['k1']$data[0][k1]。为什么我的$data 数组中的项目没有按顺序传递给value_compare_func()?例如,对于第一次迭代,我希望 $x['k1']$data[0]['k1']$y['k1']$data[1]['k1'],但事实并非如此。

【问题讨论】:

  • 您的比较功能有误。您应该在 $x
  • 看这里参考:github.com/php/php-src/blob/…,php使用的函数是这个文件中的zend_hash_sort_ex
  • 我看到手册说我的值比较函数应该返回 int 值(1-10)但使用 false 代替 -1 和 @987654348 @ 代替 1 会产生一个具有完全相同的值序列的排序数组。
  • 另外,我在每次迭代期间转储的值也不会改变。
  • 你查过我发的php源码了吗?这并不容易,但可以在那里找到快速排序的实现。无论如何,comparefunc 除了比较之外,不应该对数据做任何其他事情,我建议您不要在其中编写任何与顺序相关的代码。如果您需要特定的访问顺序,则必须实现自己的排序功能,但这会以性能为代价

标签: php arrays sorting


【解决方案1】:

这些项目如何传递给比较函数的答案需要了解quicksort algorithm。它的要点是数组中的某些元素被分配为枢轴(它实际上可以是任何元素,但在有效的实现中它通常是中间元素),然后在枢轴的任一侧进行比较以对数组。

这基本上是usort在PHP中的底层实现。

所以试图观察元素传递给比较函数的顺序是相对没有用的。顺序完全不重要。重要的是您可以放心,它们将始终根据您的 callback 函数返回的内容正确排序。

这里要注意的重要一点是,手册明确警告不要从回调中返回非整数值,因为非常具体的原因(它们将被转换为整数),在你的示例中您从回调中返回一个布尔值false,当转换为integer 时,它将变为0。由于0 表示两个值相等,因此您不会也不应该期望这里有一个正确排序的数组。

$a &gt; $b 时,始终确保返回整数值1$a &lt; $b 时返回整数值-1,当$a == $b 时返回整数值0 .

【讨论】:

  • 使用false 代替-1true 代替1 作为返回值似乎不会导致数组的排序方式与数组的排序方式有任何不同当我返回 int 值时进行排序。 Larry Ullman 在他的《PHP Advanced & OOP 3rd ed》一书中使用了bool 返回值。 bool 值是否可以接受,只是手册中没有提到?无论如何,这是我感兴趣的答案的第一部分(如何将项目传递给比较函数)。
  • 可能结果相同,但使用更新的 comp func 检查迭代
  • 我在每次迭代中转储的值也不会改变。
  • 从回调中返回布尔值false-1 绝对是重要。在您的特定示例中,排序结果没有改变只是巧合,但返回 false 绝对是错误的,因为这不是回调所期望的。您只是在发现未定义的行为。我的建议是不要依赖它。
  • @henrywright 他们可能不会改变你,但这并不意味着什么,因为再次未定义的行为 See how the order of comparison means nothing whatsoever in terms of the resulting sort 关键是你真的不应该关心自己比较它们的顺序,这是未定义的,因为您应该使用回调的返回值所期望的明确定义的行为,以便每次都获得有效的结果。
【解决方案2】:

比较函数应该返回一个数值。由于您返回布尔值,因此比较变得无法预测为false == 0,因此两者之间的区别在排序时会丢失。

您应该按如下方式更改您的代码:

function value_compare_func( $x, $y ) {
    if ( $x['k1'] > $y['k1'] ) {
        return 1;
     } elseif ( $x['k1'] < $y['k1'] ) {
         return -1;
     } else {
         return 0;
     }
 }

...结果会更合乎逻辑。

【讨论】:

    猜你喜欢
    • 2012-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 2018-02-06
    • 2020-07-10
    相关资源
    最近更新 更多