2009-07-07 89 views
11

这是一个非常深奥的问题,但我真的很好奇。我几年来第一次使用usort,并且我对究竟发生了什么特别感兴趣。假设我有以下数组:PHP的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和$湾他们是什么,他们代表什么。我的意思是,我可以假设$ 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的清晰度。我只知道匹配我正在寻找的模式。

有人可以提供一些关于实际发生的事情的清晰度吗?

+0

+1我一直都这么认为。 – alex 2010-02-18 14:02:42

回答

5

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

一旦您有办法比较两个元素,您可以使用排序算法选择

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

在幕后,PHP正在使用quicksort

+2

我相信乔纳森对“幕后”部分感兴趣。 – 2009-07-07 11:19:09

31

$ 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); 
?> 

输出

[email protected]:~$ 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进行比较。

一些进一步的图解说明。

 
Step 0: (1,19,18,12,56); //Pivot: 18, 
Step 1: (1,12,18,19,56); //After the first reordering 
Step 2a: (1,12);   //Recursively do the same with the lesser, here 
         //pivot's 12, and that's what it compares next if 
         //you check the output. 
Step 2b: (19,56);  //and do the same with the greater 
+0

优秀的答案。保罗是足够的,第一。所以我给他接受了。我赞成你的意见,并感谢你的彻底。 – Sampson 2009-07-07 12:57:06

0

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'。

我把它称为人类感觉错误,因为它取决于你使用的是什么情况以及你觉得它应该在现实世界中进行排序,当比较值相同时。