indietro

  • sort NOMESUB LISTA
  • sort BLOCCO LISTA
  • sort LISTA

    In un contesto di lista, ordina la LISTA e restituisce il valore della lista ordinata. In un contesto scalare il comportamento di sort() è indefinito.

    Se NOMESUB o BLOCCO vengono omessi, ordina secondo il confronto standard tra stringhe. Se NOMESUB viene specificato, esso fornisce il nome di una subroutine che restituisce un intero minore, uguale o maggiore di 0 a seconda di come gli elementi della lista devono essere ordinati. (Gli operatori <=> e cmp sono estremamente utili in tali routine). NOMESUB può essere il nome di una variabile scalare (senza indici di array o chiavi di hash), nel qual caso il valore fornisce il nome (o un riferimento) della subroutine che si deve in effetti usare. Al posto di NOMESUB si può fornire un BLOCCO in qualità di subroutine anonima, interna.

    Se il prototipo della subroutine è ($$), gli elementi da confrontare sono passati per riferimento in @_, come accade per una normale subroutine. Ciò è più lento rispetto ad una subroutine senza prototipo, dove gli elementi da confrontare sono passati alla subroutine nelle variabili package globali $a e $b (guardate l'esempio sottostante). Va notato che in quest'ultimo caso è tipicamente controproducente dichiarare $a e $b come lessicali.

    In entrambi i casi la subroutine non può essere ricorsiva. I valori da confrontare sono sempre passati per riferimento, quindi non dovrebbero essere modificati.

    Inoltre, non potte uscire dal blocco o dalla subroutine di ordinamento usando uno degli operatori di controllo del ciclo descritti in perlsyn o con goto.

    Quando use locale è attivo, sort LISTA ordina la lista secondo il riscontro del "locale" corrente. Consultate perllocale.

    sort() restituisce gli alias alla lista originaria, così come una variabile indice del ciclo for restituisce degli alias agli elementi della lista.

    Cioè, modificare un elemento di una lista restituita da sort() (per esempio, in un foreach, map o grep) modifica proprio l'elemento della lista originare

    much as a for loop's index variable aliases the list elements. That is, modifying an element of a list returned by sort() (for example, in a foreach, map or grep) actually modifies the element in the original list. This is usually something to be avoided when writing clear code.

    Perl 5.6 e le versioni precedenti usavano l'algoritmo quicksort per implementare l'ordinamento. Quell'algoritmo non era stabile, e avrebbe potuto avere un comportamento quadratico. (Un ordinamento stabile preserva l'ordine degli elementi in input che risultano uguali. Benché il tempo d'esecuzione di quicksort sia O(NlogN) in media su tutti gli array di lunghezza N, il tempo può essere O(N**2), ovvero comportarsi quadraticamente, per alcuni input). Nella versione 5.7, l'implementazione di quicksort è stata rimpiazzata da un algoritmo mergesort stabile il cui comportamento nel caso pessimo è O(NlogN). Ma i benchmark indicavano che per alcuni input, su alcune piattaforme, il quicksort originale andava più veloce. La versione 5.8 ha una direttiva sort che consente un limitato controllo su sort. Il suo blando controllo dell'algoritmo sottostante potrebbe scomparire nelle prossime versioni di Perl, ma l'abilità di caratterizzare l'input e l'output in modi indipendenti dall'implementazione probabilmente non lo farà. Consultate sort.

    Esempi:

        # ordinamento lessicale
        @articoli = sort @file;
        # stessa cosa, ma con una routine esplicita di ordinamento
        @articoli = sort {$a cmp $b} @file;
        # ora senza tener conto di maiuscole e minuscole
        @articoli = sort {uc($a) cmp uc($b)} @file;
        # stessa cosa in ordine inverso
        @articoli = sort {$b cmp $a} @file;
        # ordinamento numerico ascendente
        @articoli = sort {$a <=> $b} @file;
        # ordinamento numerico discendente
        @articoli = sort {$b <=> $a} @file;
        # ordina l'hash %eta per valore anziche' per chiave
        # usando una funzione interna
        @prima_gli_anziani = sort { $eta{$b} <=> $eta{$a} } keys %eta;
        # ordina usando il nome della subroutine esplicito
        sub pereta {
            $eta{$a} <=> $eta{$b};  # si assume siano chiavi numeriche
        }
        @classe_ordinata = sort pereta @classe;
        sub alcontrario { $b cmp $a }
        @harry  = qw(cane gatto x Caino Abele);
        @george = qw(andato inseguito yz Punito Accettato);
        print sort @harry;
            # stampa AbelCaincatdogx AbeleCainocanegattox
        print sort alcontrario @harry;
            # stampa xdogcatCainAbel xgattocaneCainoAbele
        print sort @george, 'to', @harry;
            # stampa AbeleAccettatoCainoPunitoandatocanegattoinseguitotoxyz
        # ordinamento inefficiente ottenuto per confronto
        # numerico discendente del primo numero dopo
        # il primo segno =, o altrimenti per confronto
        # di tutto il record, senza tener conto di
        # maiuscole e minuscole
        @nuovo = sort {
        ($b =~ /=(\d+)/)[0] <=> ($a =~ /=(\d+)/)[0]
                            ||
                    uc($a)  cmp  uc($b)
        } @vecchio;
        # stessa cosa, ma in maniera molto piu` efficiente;
        # costruiamo indici ausiliari, per aumentare la
        # velocita`
        @numeri = @inmaiuscolo = ();
        for (@vecchio) {
          push @numeri, /=(\d+)/;
          push @inmaiuscolo, uc($_);
        }
        @nuovo = @vecchio[ sort {
                                  $numeri[$b] <=> $numeri[$a]
                                              ||
                                     $caps[$a] cmp $caps[$b]
                                } 0..$vecchio
                         ];
        # stessa cosa, ma senza variabili temporanee
        @nuovo = map { $_->[0] }
                 sort { $b->[1] <=> $a->[1]
                                 ||
                        $a->[2] cmp $b->[2]
                 } map { [$_, /=(\d+)/, uc($_)] } @vecchio;
        # l'uso di un prototipo consente di usare, con sort,
        # qualunque subroutine di confronto (comprese le
        # subroutine definite in altri package)
        package altro;
        sub alcontrario ($$) { $_[1] cmp $_[0]; }     # $a e $b, qui, non sono impostate
        package main;
        @nuovo = sort altro::alcontrario @vecchio;
        # stabilita` garantita, qualunque sia l'algoritmo
        use sort 'stable';
        @nuovo = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @vecchio;
        # forza l'uso di mergesort (non portabile al di 
        # fuori della versione 5.8 di Perl)
        use sort '_mergesort';  # notate il _ che ne 
                                # scoraggia l'uso
        @nuovo = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @vecchio;

    Se state usando strict, non dovete dichiarare $a e $b come lessicali. Sono variabili globali del package. Questo significa che se siete nel package main e scrivete

      @articoli = sort { $b <=> $a } @file;

    allora $a e $b sono $main::a e $main::b (o $::a e $::b), ma se siete nel package PackagePippo è lo stesso che scrivere

      @articoli = sort { $PackagePippo::b <=> $PackagePippo::a } @file;

    Si richiede che la funzione di confronto si comporti in modo consistente. Se restituisce risultati inconsistenti (dicendo a volte che $x[1] è più piccolo di $x[2] e a volte il contrario, per esempio) i risultati non sono ben definiti.

    Poiché <=> restituisce undef quando uno degli operandi è NaN (not-a-number) [non-un-numero, NdT], e poiché sort genererà un errore bloccante a meno che il risultato del confronto sia definito, quando effettuate un ordinamento con una funzione di confronto come $a <= $b>, state attenti alle liste che potrebbero contenere NaN. Il seguente esempio sfrutta il fatto che NaN != NaN, per eliminare ogni NaN dall'input.

        @risultati = sort { $a <=> $b } grep { $_ == $_ } @input;