Λίστες

sort#

Ταξινομεί μια λίστα, επιστρέφοντας την ταξινομημένη λίστα.

Η sort παίρνει μια λίστα και επιστρέφει νέα λίστα με τα στοιχεία αναδιατεταγμένα σε σειρά. Χωρίς συγκριτή χρησιμοποιεί την τυπική σύγκριση συμβολοσειρών. Με ένα BLOCK ή ένα SUBNAME παρέχετε εσείς τον κανόνα σύγκρισης ως μικρή συνάρτηση που καλείται για κάθε ζεύγος στοιχείων και πρέπει να επιστρέφει αρνητική, μηδενική ή θετική τιμή με τον τρόπο που το κάνουν τα cmp και <=>.

Η ταξινόμηση είναι σταθερή - στοιχεία που συγκρίνονται ως ίσα διατηρούν την αρχική τους σχετική σειρά. Ο αλγόριθμος είναι mergesort.

Σύνοψη#

sort LIST
sort BLOCK LIST
sort SUBNAME LIST

Τρεις ιδιωματικές μορφές:

my @out = sort @in;                        # default: string cmp, ascending
my @out = sort { $a <=> $b } @in;          # numeric, ascending
my @out = sort by_name @in;                # named comparator sub

Τι επιστρέφεται#

Μια νέα ταξινομημένη λίστα. Η sort δεν τροποποιεί την είσοδο επιτόπια. Για να αντικαταστήσετε έναν πίνακα με την ταξινομημένη του εκδοχή, εκχωρείτε πίσω:

@a = sort @a;

Σε περιβάλλον λίστας η επιστροφή είναι η ταξινομημένη λίστα. Σε βαθμωτό περιβάλλον η τιμή επιστροφής είναι απροσδιόριστη - μη χρησιμοποιείτε scalar sort.

Η επιστρεφόμενη λίστα περιέχει ψευδώνυμα προς την αρχική λίστα, ακριβώς όπως η μεταβλητή δείκτη ενός foreach. Η τροποποίηση στοιχείου του αποτελέσματος μέσα σε μεταγενέστερο foreach, map ή grep επομένως τροποποιεί και το αρχικό στοιχείο. Αυτό σχεδόν ποτέ δεν είναι αυτό που θέλετε· χειριστείτε το αποτέλεσμα ως μόνο-για-ανάγνωση.

Καθολική κατάσταση: $a και $b#

Μέσα στο BLOCK ή το SUBNAME του συγκριτή, τα δύο στοιχεία που συγκρίνονται εκτίθενται ως οι καθολικές πακέτου $a και $b. Αυτές δεν είναι παράμετροι και δεν είναι λεξιλογικές - είναι πραγματικές μεταβλητές πακέτου που η sort τοπικοποιεί για εσάς γύρω από την κλήση.

  • Οι $a και $b ζουν στο πακέτο που κάλεσε τη sort. Στο main, αυτές είναι οι $main::a και $main::b· στο Foo, οι $Foo::a και $Foo::b.

  • Ποτέ μη δηλώνετε my $a ή my $b οπουδήποτε μπορεί να δει το μπλοκ ταξινόμησης. Μια λεξιλογική $a ή $b επικαλύπτει την καθολική πακέτου· τότε το μπλοκ συγκρίνει δύο άσχετες μεταβλητές και η ταξινόμηση παράγει σιωπηλά σκουπίδια. Υπό use warnings δεν λαμβάνετε καμία προειδοποίηση γι” αυτό.

  • Αν πραγματικά χρειάζεστε τις $a / $b ως λεξιλογικές αλλού, αναφερθείτε στις μεταβλητές ταξινόμησης με το πλήρες όνομα μέσα στο μπλοκ:

    print sort { $::a cmp $::b }         qw(A C E G B D F H);
    print sort { our $a cmp our $b }     qw(A C E G B D F H);
    
  • Ένας συγκριτής που ορίζεται με prototype ($$) (ή ισοδύναμο γνώρισμα signature) λαμβάνει το ζεύγος στο @_ αντί για τα $a και $b. Αυτό είναι πιο αργό από τη σύμβαση $a/$b, αλλά αποσυνδέει την υπορουτίνα από το πακέτο του καλούντος.

Και τα δύο στοιχεία περνούν με αναφορά· η μεταβολή των $a ή $b στο μπλοκ μεταβάλλει την αρχική λίστα. Μην το κάνετε.

Παραδείγματα#

Προεπιλεγμένη ταξινόμηση συμβολοσειρών:

my @sorted = sort qw(banana apple cherry);
# ('apple', 'banana', 'cherry')

Αριθμητική αύξουσα - η προεπιλεγμένη sort @nums θα ταξινομούσε το "10" πριν το "2" επειδή η σύγκριση γίνεται ανά συμβολοσειρά:

my @nums = sort { $a <=> $b } (10, 2, 33, 4);
# (2, 4, 10, 33)

Αριθμητική φθίνουσα - αντιμεταθέστε τα $a και $b:

my @nums = sort { $b <=> $a } (10, 2, 33, 4);
# (33, 10, 4, 2)

Ταξινόμηση με πολλαπλά κλειδιά και αποκλεισμό ισοβαθμίας. Το || εκτελεί τον δεύτερο συγκριτή μόνο όταν ο πρώτος επιστρέψει 0:

my @people = sort {
    $a->{last}  cmp $b->{last}
 || $a->{first} cmp $b->{first}
} @records;

Ταξινομήστε τα κλειδιά ενός hash βάσει της σχετιζόμενης τιμής:

my %age = (alice => 30, bob => 25, carol => 40);
my @by_age = sort { $age{$a} <=> $age{$b} } keys %age;
# ('bob', 'alice', 'carol')

Schwartzian Transform - όταν το κλειδί ταξινόμησης είναι ακριβό να υπολογιστεί, προυπολογίστε το μία φορά ανά στοιχείο, ταξινομήστε τα ζεύγη [key, value], και κατόπιν αφαιρέστε τα κλειδιά. Τρία στάδια, διαβάστε από κάτω προς τα πάνω:

my @sorted =
    map  { $_->[1] }                     # 3. strip key
    sort { $a->[0] <=> $b->[0] }         # 2. sort by key
    map  { [ expensive_key($_), $_ ] }   # 1. attach key
    @input;

Ονομασμένη υπορουτίνα συγκριτή. Η υπορουτίνα διαβάζει τα $a και $b από το πακέτο του καλούντος, οπότε πρέπει να βρίσκεται (ή να αναφέρεται από) εκείνο το πακέτο:

sub by_name { $a->{name} cmp $b->{name} }

my @sorted = sort by_name @people;

Συγκριτής με prototype - τα ορίσματα φτάνουν στο @_, οπότε λειτουργεί από οποιοδήποτε πακέτο:

sub numeric ($$) { $_[0] <=> $_[1] }

my @sorted = sort numeric @nums;

Οριακές περιπτώσεις#

  • Οι $a και $b είναι καθολικές πακέτου, όχι λεξιλογικές. Ένα αδέσποτο my $a στην εμβέλεια σπάει σιωπηλά κάθε ταξινόμηση σε εκείνη την εμβέλεια. Αν πρέπει, χρησιμοποιήστε our $a ή $::a μέσα στο μπλοκ.

  • Το <=> είναι αριθμητικό, το cmp είναι συμβολοσειράς. Η χρήση του λάθος είναι το πιο κοινό σφάλμα ταξινόμησης. Η sort { $a cmp $b } (10, 2, 33) δίνει (10, 2, 33) - λεξικογραφικά, το "10" πριν το "2". Χρησιμοποιήστε <=> για αριθμούς.

  • Κενή λίστα επιστρέφει κενή λίστα. Η sort () είναι (). Κανένα σφάλμα.

  • Ένα μόνο στοιχείο επιστρέφεται αμετάβλητο. Δεν γίνεται καμία σύγκριση.

  • Ο συγκριτής πρέπει να είναι συνεπής. Αν κάποτε λέει $x < $y και κάποτε το αντίθετο για το ίδιο ζεύγος, το αποτέλεσμα είναι απροσδιόριστο. Ο συγκριτής πρέπει να επιστρέφει ολική διάταξη: αρνητικό, μηδέν ή θετικό, με σταθερό τρόπο, για κάθε κλήση.

  • Το NaN δηλητηριάζει το <=>. Η $a <=> $b επιστρέφει undef αν οποιοσδήποτε από τους τελεστέους είναι NaN, την οποία η sort στη συνέχεια χειρίζεται ως 0 - ίσα - δίνοντας αυθαίρετη τοποθέτηση. Φιλτράρετε πρώτα:

    my @clean = sort { $a <=> $b } grep { $_ == $_ } @input;
    
  • Σταθερή ταξινόμηση. Τα ίσα στοιχεία διατηρούν τη σειρά εισόδου τους. Βασιστείτε σε αυτό για ταξινομήσεις πολλαπλών περασμάτων (ταξινομήστε πρώτα κατά δευτερεύον κλειδί, μετά κατά πρωτεύον). Η use sort 'stable' είναι η προεπιλογή και no-op· οι pragmas use sort '_mergesort' / '_qsort' είναι ιστορικές και δεν έχουν επίδραση στην τρέχουσα Perl.

  • Η sort δεν είναι επιτόπια. Η sort @a δεν αγγίζει το @a. Χρησιμοποιήστε @a = sort @a για να το αντικαταστήσετε. Η εκχώρηση στη λίστα αποτελέσματος της sort ψευδωνυμοποιεί πίσω στο αρχικό, οπότε η (sort @a)[0] = ... τροποποιεί το μικρότερο στοιχείο του @a.

  • No loop control out of the block. last, next, redo, return, and goto LABEL do not work inside a sort comparator

    • the block is not a loop body.

  • Παγίδα αναλυτή: ταξινόμηση της τιμής επιστροφής συνάρτησης. Η sort παίρνει LIST, οπότε ένα ακολουθούμενο bareword μπορεί να εκληφθεί ως SUBNAME. Για να ταξινομήσετε το αποτέλεσμα της find_records(@key):

    my @out = sort { $a cmp $b } find_records @key;   # OK
    my @out = sort +find_records(@key);               # OK
    my @out = sort(find_records(@key));               # OK
    

    Για να χρησιμοποιήσετε την find_records ως συγκριτή επί του @key αντ” αυτού:

    my @out = sort find_records @key;                 # comparator form
    my @out = sort { find_records() } @key;           # block form
    
  • Ταξινόμηση με επίγνωση locale. Υπό use locale (χωρίς ':not_characters') η προεπιλεγμένη σύγκριση συμβολοσειρών ακολουθεί το τρέχον locale συνταξιοθεσίας αντί για τη σειρά σημείων κώδικα.

  • Συγκριτές XSUB. Αν ο συγκριτής είναι XSUB, το ζεύγος περνά στη στοίβα ορισμάτων με τον τρόπο που οι συναρτήσεις XS συνήθως λαμβάνουν ορίσματα· οι $a και $b δεν ορίζονται.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • reverse - αντιστρέφει μια λίστα· συνδυάστε με τη sort για φθίνουσες ταξινομήσεις όταν ο συγκριτής δύσκολα αντιστρέφεται με αντιμετάθεση των $a και $b

  • map - το άλλο μισό του Schwartzian Transform· χρησιμοποιήστε για να επισυνάψετε και να αφαιρέσετε κλειδιά ταξινόμησης γύρω από μια sort

  • grep - προφιλτράρετε τη λίστα (π.χ. αφαιρέστε NaN ή undef) πριν την παραδώσετε στη sort

  • $a - το πρώτο στοιχείο στο ζεύγος σύγκρισης, ψευδωνυμοποιημένο ως καθολική πακέτου για τη διάρκεια της ταξινόμησης

  • $b - το δεύτερο στοιχείο στο ζεύγος σύγκρισης, με τους ίδιους κανόνες διάρκειας ζωής και εμβέλειας με την $a

  • <=> - αριθμητική τρίτιμη σύγκριση· ο συνηθισμένος τελεστής μέσα σε αριθμητικό μπλοκ ταξινόμησης

  • cmp - τρίτιμη σύγκριση συμβολοσειρών· ο συνηθισμένος τελεστής μέσα σε μπλοκ ταξινόμησης συμβολοσειρών