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;


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow