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· οι pragmasuse 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, andgoto LABELdo not work inside a sort comparatorthe 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και$bmap- το άλλο μισό του Schwartzian Transform· χρησιμοποιήστε για να επισυνάψετε και να αφαιρέσετε κλειδιά ταξινόμησης γύρω από μιαsortgrep- προφιλτράρετε τη λίστα (π.χ. αφαιρέστεNaNήundef) πριν την παραδώσετε στηsort$a- το πρώτο στοιχείο στο ζεύγος σύγκρισης, ψευδωνυμοποιημένο ως καθολική πακέτου για τη διάρκεια της ταξινόμησης$b- το δεύτερο στοιχείο στο ζεύγος σύγκρισης, με τους ίδιους κανόνες διάρκειας ζωής και εμβέλειας με την$a<=>- αριθμητική τρίτιμη σύγκριση· ο συνηθισμένος τελεστής μέσα σε αριθμητικό μπλοκ ταξινόμησηςcmp- τρίτιμη σύγκριση συμβολοσειρών· ο συνηθισμένος τελεστής μέσα σε μπλοκ ταξινόμησης συμβολοσειρών