【问题标题】:PHP's USORT Callback Function ParametersPHP的USORT回调函数参数
【发布时间】:2010-11-08 16:04:42
【问题描述】:

这是一个非常深奥的问题,但我真的很好奇。我多年来第一次使用 usort,我对到底发生了什么特别感兴趣。假设我有以下数组:

$myArray = array(1, 9, 18, 12, 56);

我可以用 usort 排序:

usort($myArray, function($a, $b){
  if ($a == $b) return 0;
  return ($a < $b) ? -1 : 1;
});

我不是 100% 清楚 $a 和 $b 这两个参数发生了什么。它们是什么,它们代表什么。我的意思是,我可以假设 $a 代表数组中的当前项,但与此相比究竟是什么? $b 是什么?

我可以增加我的数组以包含字符串:

$myArray = array(
  array("Apples", 10),
  array("Oranges", 12),
  array("Strawberries", 3)
);

然后运行以下命令:

usort($myArray, function($a, $b){
  return strcmp($a[0], $b[0]);
});

这将根据 [0] 索引值按字母顺序对我的子数组进行排序。但这并没有明确说明 $a 和 $b 是什么。我只知道匹配我正在寻找的模式。

有人可以说明实际发生的情况吗?

【问题讨论】:

  • +1 我一直这么认为。

标签: php usort


【解决方案1】:

$a 和 $b 的确切定义取决于用于对数组进行排序的算法。要对任何内容进行排序,您必须有一种方法来比较两个元素,这就是回调函数的用途。一些排序算法可以从数组中的任何位置开始,而另一些只能从数组的特定部分开始,因此在 $a 和 $b 中没有 固定 含义,除了它们是数组中必须根据当前算法进行比较。

此方法可用于阐明 PHP 正在使用哪种算法。

<?php

$myArray = array(1, 19, 18, 12, 56);

function compare($a, $b) {
    echo "Comparing $a to $b\n";
    if ($a == $b) return 0;
    return ($a < $b) ? -1 : 1;
}

usort($myArray,"compare");
print_r($myArray);
?>

输出

vinko@mithril:~$ php sort.php
Comparing 18 to 19
Comparing 56 to 18
Comparing 12 to 18
Comparing 1 to 18
Comparing 12 to 1
Comparing 56 to 19
Array
(
    [0] => 1
    [1] => 12
    [2] => 18
    [3] => 19
    [4] => 56
)

从输出和查看源代码我们可以看到使用的排序确实是quicksort 实现,检查PHP 源代码中的Zend/zend_qsort.c(链接到的版本有点旧,但没有太大变化)。

它选择数组中间的枢轴,在本例中为 18,然后它需要重新排序列表,以便所有小于枢轴的元素(根据使用的比较函数)位于枢轴之前,并且这样所有大于枢轴的元素都在它之后,当它首先将所有内容与 18 进行比较时,我们可以看到它这样做了。

一些进一步的图解说明。

步骤0:(1,19,18,12,56); //枢轴:18, 第一步:(1,12,18,19,56); //第一次重新排序后 步骤 2a:(1,12); //递归地对较小的做同样的事情,这里 //pivot 是 12,这就是接下来要比较的 if //你检查输出。 步骤 2b:(19,56); //对更大的做同样的事情

【讨论】:

  • 优秀的答案。保罗的就足够了,而且是第一。所以我给了他录取。不过,我对你的投票表示赞同,并感谢你的彻底性。
  • 为了争论,我建议首先并不总是更好。如果第二个答案更完整,则应该奖励花时间完整回答问题的人。
【解决方案2】:

要对任何内容进行排序,您需要一种方法来比较两个项目并确定一个是否在另一个之前。这是您提供给 usort 的。此函数将从您的输入数组中传递两个项目,并返回它们应该在的顺序。

一旦你有办法比较两个元素,你就可以使用 sort-algorithm-of-your-choice。

如果您不熟悉,您可能想看看像bubblesort 这样的简单朴素算法如何使用比较函数。

在幕后,PHP 使用的是quicksort。

【讨论】:

  • 我相信乔纳森对“幕后”部分很感兴趣。
【解决方案3】:

usort() 或 uasort() 在排序结果上有一个人类感觉的错误。见代码段:

function xxx($a,$b) { if ($a==$b) return 0; else return $a<$b?-1:1; }
$x=array(1=>10,2=>9,3=>9,4=>9,5=>6,6=>38);
uasort($x,'xxx');
print_r($x);

结果是:

Array ( [5] => 6 [4] => 9 [3] => 9 [2] => 9 [1] => 10 [6] => 38 )

你看到错误了吗?不?好吧,让我解释一下。 最初的三个“9”元素按键顺序排列:2、3、4。但结果中,三个 '9' 元素现在是键序:4,3,2,即等值元素排序后键序相反。

如果元素只有单个值,如上例所示,我们可以。但是,如果元素是复合值,那么它可能会导致人类感觉错误。查看另一个代码段。我们要对许多点进行水平排序,即根据升序的 x 坐标值顺序对它们进行排序:

function xxx($a,$b) { if ($a['x']==$b['x']) return 0; else return $a['x']<$b['x']?-1:1; }
$x=array(1=>array('x'=>1, 'v'=>'l'),2=>array('x'=>9, 'v'=>'love'),
       3=>array('x'=>9,  'v'=>'Lara'),4=>array('x'=>9,  'v'=>'Croft'),
       5=>array('x'=>15,  'v'=>'and'),6=>array('x'=>38,  'v'=>'Tombraider'));
uasort($x,'xxx');
print_r($x);

结果是:

Array ( [1] => Array ( [x] => 1 [v] => l ) [4] => Array ( [x] => 9 [v] => croft ) 
             [3] => Array ( [x] => 9 [v] => Lara ) [2] => Array ( [x] => 9 [v] => love )
             [5] => Array ( [x] => 15 [v] => and ) [6] => Array ( [x] => 38 [v] => Tombraider ) )

您会看到“我爱劳拉和 Tombraider”变成了“我爱劳拉和 Tombraider” .

我称之为人类感觉错误,因为它取决于您使用的案例以及当比较值相同时您在现实世界中应该如何排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-14
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多