2009-07-07 17 views
11

To naprawdę ezoteryczne pytanie, ale jestem naprawdę ciekawy. Korzystam z usort po raz pierwszy od wielu lat i jestem szczególnie zainteresowany tym, co się dzieje. Załóżmy, że mam następującą tablicę:Parametry funkcji zwrotnej USORT w PHP

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

mogłem uporządkować to z usort:

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

nie jestem w 100% jasne, co się dzieje z tymi dwoma parametrami $ ai $ b. Czym są i co reprezentują. To znaczy, mógłbym założyć, że $ a reprezentuje bieżący element w tablicy, ale do czego dokładnie się to porównuje? Co to jest $ b?

mogę zwiększyć swoją tablicę zawierać ciągi:

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

i uruchom następujące:

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

A to uporządkować moje Rodziny z tablic alfabetycznie oparte na [0] wartość indeksu. Ale to nie daje żadnej jasności co do wartości $ a i $ b. Wiem tylko, że pasuje do wzoru, którego szukam.

Czy ktoś może wyjaśnić, co faktycznie ma miejsce?

+0

+1 Zawsze myślałem tak samo. – alex

Odpowiedz

5

Aby posortować wszystko, musisz porównać dwa elementy i dowiedzieć się, czy jeden przychodzi przed drugim. To właśnie dostarczasz do usortowania. Ta funkcja zostanie przekazana dwóm elementom z twojej tablicy wejściowej i zwrócona zostanie kolejność, w jakiej powinny być.

Po wybraniu dwóch elementów możesz użyć algorytmu sortowania według Twojego wyboru.

Jeśli nie jesteś zaznajomiony, możesz sprawdzić, jak prosty algorytm naiwny, taki jak bubblesort, użyłby funkcji porównania.

Za kulisami PHP używa nazwy quicksort.

+2

Wierzę, że Jonathan interesuje się częścią "za kulisami". –

31

Dokładna definicja $ ai $ b będzie zależeć od algorytmu użytego do posortowania tablicy. Aby posortować cokolwiek, musisz mieć możliwość porównania dwóch elementów, do czego służy funkcja wywołania zwrotnego. Niektóre algorytmy sortowania mogą rozpoczynać się w dowolnym miejscu w tablicy, inne mogą rozpoczynać się tylko w określonej części, więc nie ma stałej wartościw $ a i $ b innych niż dwa elementy w tablicy, które muszą być aktualny algorytm.

Ta metoda może być użyta do rzucenia światła na algorytm używany przez 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); 
?> 

Wyjście

[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 
) 

Z wyjścia i patrząc na źródło widzimy sortować używane jest rzeczywiście realizacja quicksort, sprawdź Zend/zend_qsort.c w źródle PHP (połączonej wersji jest nieco stare, ale niewiele się zmieniło).

Wybiera pivot w środku tablicy, w tym przypadku 18, następnie musi zmienić kolejność listy tak, aby wszystkie elementy, które są mniejsze (zgodnie z używaną funkcją porównania), były przestawiane przed osią obrotu i tak, że wszystkie elementy większe niż pivot przychodzą po nim, widzimy, że robi to, gdy porównuje wszystko do 18 na początku.

Niektóre dalsze wyjaśnienia schematyczne.

 
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

Doskonała odpowiedź. Paweł był wystarczający i pierwszy. Dlatego przyznałem mu akceptację. Przegapiłem twoje i doceniam twoją dokładność. – Sampson

+7

Ze względu na argument, sugeruję, że najpierw nie zawsze jest lepiej. Jeśli druga odpowiedź jest bardziej kompletna, ludzie powinni zostać nagrodzeni za poświęcenie czasu na pełne udzielenie odpowiedzi na to pytanie. – acrosman

0

usort() lub uasort() mają błąd człowieka uczucie na wynik sortowane. Zobacz segment kodu:

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

wynikiem jest:

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

Czy widzisz błąd? Nie? Ok, pozwól mi to wyjaśnić. Oryginalne trzy "9" są w kolejności: 2, 3, 4. Ale w rezultacie trzy elementy "9" są teraz w kluczowej kolejności: 4,3,2, tj. Elementy o równej wartości są w kolejności odwrotnej po sortowaniu.

Jeśli element jest tylko pojedynczą wartością, tak jak w powyższym przykładzie, nie ma problemu z nami. Jednakże, jeśli element ma wartość złożoną, może powodować u człowieka błąd. Zobacz inne segmenty kodu. Jesteśmy uporządkować wiele punktów w poziomie, tzn sortować je na podstawie rosnącej współrzędna x wartość zamówienia:

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

wynikiem jest:

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)) 

Widzisz 'Kocham Larę Croft i Tombraider "staje się" I Croft Lara love and Tombraider ".

Nazywam to ludzkim uczuciem błędu, ponieważ zależy to od używanego przypadku i od tego, jak się czuje, powinno być posortowane w świecie rzeczywistym, gdy porównywane wartości są takie same.

Powiązane problemy