这是一个非常深奥的问题,但我真的很好奇。我今天第一次使用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是什么。我只知道匹配我正在寻找的模式。
有人可以清楚说明实际发生的事情吗?
答案 0 :(得分:31)
$ a和$ b的确切定义将取决于用于对数组进行排序的算法。要对任何东西进行排序,你必须有一种方法来比较两个元素,这就是回调函数的用途。一些排序算法可以从数组中的任何地方开始,其他排序算法只能在它的特定部分开始,因此除了它们是数组中必须的两个元素之外,$ a和$ b中没有 fixed 意义。根据当前的算法进行比较。
此方法可用于阐明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进行比较时就这样做了。
进一步的图解说明。
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
答案 1 :(得分:5)
要对任何东西进行排序,您需要一种方法来比较两个项目,并找出一个项目是否先于另一个项目。这是你提供给我们的。此函数将从输入数组中传递两个项目,并返回它们应该处于的顺序。
一旦有了比较两个元素的方法,就可以使用 sort-algorithm-of-your-choice 。
如果您不熟悉,您可能想看看像bubblesort这样的简单朴素算法如何使用比较函数。
在幕后,PHP正在使用quicksort。
答案 2 :(得分: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 )
你看到了这个bug吗?没有?好的,我来解释一下。 原来的三个&#39; 9&#39;元素按顺序排列:2,3,4。但在结果中,三个&#9; 9&#39;元素现在按键顺序排列: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 ) )
你看&#39; 我喜欢Lara Croft和Tombraider &#39;成为&#39; I Croft Lara love and Tombraider &#39;。
我将其称为人类感觉错误,因为它取决于您使用的情况以及当比较值相同时您认为它应该在现实世界中进行排序的方式。