Perl Language
Ordinamento
Ricerca…
introduzione
Per ordinare gli elenchi di cose, Perl ha solo una singola funzione, che inaspettatamente si chiama sort
. È abbastanza flessibile da ordinare tutti i tipi di elementi: numeri, stringhe in qualsiasi numero di codifiche, strutture di dati o oggetti nidificati. Tuttavia, grazie alla sua flessibilità, ci sono alcuni trucchi e idiomi da imparare per il suo uso.
Sintassi
- ordina LISTA NOME
- ordina la BLOCCO ELENCO
- ordina LISTA
Ordinamento lessicale di base
@sorted = sort @list;
@sorted = sort { $a cmp $b } @list;
sub compare { $a cmp $b }
@sorted = sort compare @list;
I tre esempi sopra fanno esattamente la stessa cosa. Se non si fornisce alcuna funzione di confronto o blocco, l' sort
presuppone che l'elenco alla sua destra sia ordinato in modo lessicale. Di solito è la forma che desideri se hai bisogno dei tuoi dati in un ordine prevedibile e non ti preoccupi della correttezza linguistica.
sort
passa coppie di elementi nella @list
alla funzione comparatore che indica sort
quale elemento è più grande. L'operatore cmp
fa ciò per le stringhe mentre <=>
fa la stessa cosa per i numeri. Il comparatore viene chiamato abbastanza spesso, in media n * log ( n ) volte con n come numero di elementi da ordinare, quindi è importante che sia veloce. Questa è la ragione per cui l' sort
utilizza le variabili globali predefinite del pacchetto ( $a
e $b
) per passare gli elementi da confrontare al blocco o alla funzione, invece dei parametri di funzione appropriati.
Se si use locale
, cmp
prende specifico ordine di collazione locale in considerazione, ad esempio, sarà ordinare Å
come A
sotto un locale danese, ma dopo Z
sotto un inglese o un tedesco. Tuttavia, non prende in considerazione le regole di ordinamento Unicode più complesse né offre alcun controllo sull'ordine, ad esempio le rubriche telefoniche sono spesso ordinate in modo diverso dai dizionari. In questi casi, sono consigliati i moduli Unicode::Collate
e in particolare Unicode::Collate::Locale
.
Ordinamento numerico
@sorted = sort { $a <=> $b } @list;
Il confronto tra $a
e $b
con l'operatore <=>
garantisce che vengano confrontati numericamente e non testualmente come per impostazione predefinita.
Ordinamento inverso
@sorted = sort { $b <=> $a } @list;
@sorted = reverse sort { $a <=> $b } @list;
Ordinare gli articoli in ordine decrescente può essere semplicemente ottenuto scambiando $a
e $b
nel blocco comparatore. Tuttavia, alcune persone preferiscono la chiarezza di un reverse
separato anche se è leggermente più lento.
La trasformazione di Schwartz
Questo è probabilmente l'esempio più famoso di ottimizzazione del tipo che utilizza le strutture di programmazione funzionale di Perl, da utilizzare laddove l'ordinamento degli articoli dipende da una funzione costosa.
# What you would usually do
@sorted = sort { slow($a) <=> slow($b) } @list;
# What you do to make it faster
@sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, slow($_) ] }
@list;
Il problema con il primo esempio è che il comparatore viene chiamato molto spesso e continua a ricalcolare i valori usando una funzione lenta più e più volte. Un esempio tipico sarebbe l'ordinamento dei nomi dei file in base alla loro dimensione del file:
use File::stat;
@sorted = sort { stat($a)->size <=> stat($b)->size } glob "*";
Questo funziona, ma nella migliore delle ipotesi comporta il sovraccarico di due chiamate di sistema per confronto, nel peggiore dei casi deve andare sul disco, due volte, per ogni singolo confronto, e quel disco potrebbe trovarsi in un file server sovraccarico dall'altra parte del pianeta.
Inserisci il trucco di Randall Schwartz.
La Trasformata di Schwartz significa sostanzialmente @list
attraverso tre funzioni, dal basso verso l'alto. La prima map
trasforma ogni voce in una lista di due elementi dell'elemento originale e il risultato della funzione lenta come una chiave di ordinamento, quindi alla fine di questo abbiamo chiamato slow()
esattamente una volta per ogni elemento. Il seguente sort
può quindi semplicemente accedere alla chiave di ordinamento guardando nella lista. Poiché non ci interessano le chiavi di ordinamento, ma solo gli elementi originali sono ordinati in ordine, la map
finale getta via gli elenchi di due elementi dall'elenco già ordinato che riceve da @sort
e restituisce un elenco di solo i loro primi membri .
Ordinamento non sensibile al maiuscolo / minuscolo
La tecnica tradizionale per rendere il caso di ignorare l' sort
è passare le stringhe a lc
o uc
per il confronto:
@sorted = sort { lc($a) cmp lc($b) } @list;
Funziona su tutte le versioni di Perl 5 ed è completamente sufficiente per l'inglese; non importa se usi uc
o lc
. Tuttavia, presenta un problema per le lingue come il greco o il turco dove non c'è corrispondenza 1: 1 tra lettere maiuscole e minuscole in modo da ottenere risultati diversi a seconda che si usi uc
o lc
. Pertanto, Perl 5.16 e versioni successive hanno una funzione di piegatura del caso chiamata fc
che evita questo problema, quindi il moderno ordinamento multilingue dovrebbe usare questo:
@sorted = sort { fc($a) cmp fc($b) } @list;