2009-07-07 12 views
11

Questa è una domanda davvero esoterica, ma sono sinceramente curioso. Sto usando usort per la prima volta oggi da anni, e sono particolarmente interessato a cosa sta succedendo esattamente. Supponiamo che io ho il seguente array:Parametri funzione callback USORT di PHP

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

ho potuto risolvere la questione con usort:

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

io non sono al 100% chiaro su quello che sta succedendo con i due parametri $ A e $ b. Cosa sono e cosa rappresentano. Voglio dire, posso supporre che $ a rappresenti l'articolo corrente nell'array, ma a cosa si sta paragonando esattamente? Cos'è $ b?

ho potuto aumentare il mio gamma per includere stringhe:

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

ed eseguire il seguente:

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

e che sarebbe ordinare il mio bambino-array in ordine alfabetico basati sul [0] valore di indice. Ma questo non offre alcuna chiarezza su cosa siano $ a e $ b. So solo che combaciano con lo schema che sto cercando.

Qualcuno può offrire una certa chiarezza su ciò che sta effettivamente avvenendo?

+0

+1 Ho sempre pensato la stessa cosa. – alex

risposta

5

Per ordinare qualsiasi cosa è necessario un mezzo per confrontare due elementi e capire se uno viene prima dell'altro. Questo è ciò che fornisci a usort. Questa funzione passerà due elementi dall'array di input e restituirà l'ordine in cui dovrebbero essere.

Una volta che si dispone di un mezzo per confrontare due elementi, è possibile utilizzare l'algoritmo di ordinamento .

Se non si ha familiarità, si potrebbe voler vedere come un semplice algoritmo ingenuo come bubblesort utilizza una funzione di confronto.

Dietro le quinte, PHP utilizza uno quicksort.

+2

Credo che Jonathan sia interessato alla parte "dietro le quinte". –

31

L'esatta definizione di $ a e $ b dipenderà dall'algoritmo utilizzato per ordinare l'array. Per ordinare qualsiasi cosa devi avere un mezzo per confrontare due elementi, questo è ciò per cui viene utilizzata la funzione di callback. Alcuni algoritmi di ordinamento possono iniziare in qualsiasi punto dell'array, altri possono iniziare solo in una parte specifica di esso, quindi non c'è corretto in in $ a e $ b tranne che sono due elementi dell'array che devono essere confrontati in base al algoritmo attuale.

Questo metodo può essere utilizzato per far luce su quale algoritmo PHP sta usando.

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

uscita

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

Dall'output e guardando la fonte possiamo vedere il tipo usato è davvero un'implementazione quicksort, verificare la presenza di Zend/zend_qsort.c nella sorgente PHP (il legato alla versione è un po ' vecchio, ma non è cambiato molto).

Seleziona il perno nel mezzo dell'array, in questo caso 18, quindi è necessario riordinare l'elenco in modo che tutti gli elementi che sono meno (in base alla funzione di confronto in uso) rispetto al pivot vengano prima del pivot e così tutti gli elementi più grandi del perno vengono dopo di esso, possiamo vederlo farlo quando confronta tutto a 18 in un primo momento.

Alcune ulteriori spiegazioni schematiche.

 
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

Ottima risposta. Paul è stato sufficiente, e prima. Perciò gli ho assegnato l'accettazione. Ho svalutato la tua però e apprezzo la tua completezza. – Sampson

+7

Per amor di discussione, suggerirei che per prima cosa non è sempre meglio. Se la seconda risposta è più completa, le persone dovrebbero essere ricompensate per aver dedicato del tempo a rispondere pienamente alla domanda. – acrosman

0

usort() o uasort() hanno un bug uomo-sensazione su risultati ordinato. Vedere il segmento di codice:

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

il risultato è:

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

Vedete il bug? No? Ok, lascia che ti spieghi. I tre originali '9' sono in ordine di chiave: 2,3,4. Ma nel risultato, i tre elementi '9' sono ora in ordine chiave: 4,3,2, cioè gli elementi di valore uguale sono in ordine inverso dopo l'ordinamento.

Se l'elemento è solo un valore, come nell'esempio sopra, per noi va bene. Tuttavia, se l'elemento è un valore composto, potrebbe causare un bug di tipo human-feeling. Guarda un altro segmento di codice. Siamo a risolvere molti punti in orizzontale, cioè sorta loro sulla base di ascendente coordinata x ordine di valore:

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

il risultato è:

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

Vedete 'amo Lara Croft e Tombraider 'diventa' I Croft Lara love e Tombraider '.

Io lo chiamo bug di sensazioni umane perché dipende dal caso in cui si utilizza e da come si ritiene debba essere ordinato nel mondo reale quando i valori confrontati sono uguali.

Problemi correlati