2009-07-07 92 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'。

我把它稱爲人類感覺錯誤,因爲它取決於你使用的是什麼情況以及你覺得它應該在現實世界中進行排序,當比較值相同時。