Perl Language
sorteer-
Zoeken…
Invoering
Voor het sorteren van lijsten met dingen heeft Perl slechts één functie, niet voor niets sort
. Het is flexibel genoeg om allerlei items te sorteren: getallen, tekenreeksen in een willekeurig aantal coderingen, geneste gegevensstructuren of objecten. Vanwege de flexibiliteit zijn er echter nogal wat trucs en idioom te leren voor het gebruik ervan.
Syntaxis
- sorteer SUBNAAM LIJST
- sorteer BLOKLIJST
- sorteer LIJST
Basic Lexical Sort
@sorted = sort @list;
@sorted = sort { $a cmp $b } @list;
sub compare { $a cmp $b }
@sorted = sort compare @list;
De drie bovenstaande voorbeelden doen precies hetzelfde. Als u geen vergelijkingsfunctie of blok sort
gaat sort
ervan uit dat u de lijst aan de rechterkant lexisch wilt sort
. Dit is meestal de vorm die u wilt als u uw gegevens alleen in een voorspelbare volgorde nodig hebt en niet geïnteresseerd bent in taalkundige correctheid.
sort
geeft paren items in @list
aan de comparatorfunctie, die sort
welk item groter is. De cmp
operator doet dit voor tekenreeksen, terwijl <=>
hetzelfde doet voor getallen. De comparator wordt vaak genoemd, gemiddeld n * log ( n ) keer waarbij n het aantal te sorteren elementen is, dus het is belangrijk dat het snel is. Dit is de reden waarom sort
vooraf gedefinieerde pakket globale variabelen ( $a
en $b
) gebruikt om de elementen door te geven die moeten worden vergeleken met het blok of de functie, in plaats van de juiste functieparameters.
Als u use locale
, houdt cmp
rekening met de locale specifieke sorteervolgorde, het sorteert bijvoorbeeld Å
zoals A
onder een Deense locale maar na Z
onder een Engelse of Duitse. Het houdt echter geen rekening met de complexere Unicode-sorteerregels en biedt ook geen controle over de bestelling. Telefoonboeken worden bijvoorbeeld vaak anders gesorteerd dan woordenboeken. Voor die gevallen worden de Unicode::Collate
en in het bijzonder Unicode::Collate::Locale
modules aanbevolen.
Numeriek sorteren
@sorted = sort { $a <=> $b } @list;
Als u $a
en $b
met de operator <=>
, zorgt u ervoor dat ze numeriek en niet standaard worden vergeleken.
Omgekeerd sorteren
@sorted = sort { $b <=> $a } @list;
@sorted = reverse sort { $a <=> $b } @list;
Sorteer items in aflopende volgorde eenvoudig door $a
en $b
in het vergelijkingsblok te verwisselen. Sommige mensen geven echter de voorkeur aan de duidelijkheid van een afzonderlijke reverse
, hoewel deze iets langzamer is.
De Schwartziaanse transformatie
Dit is waarschijnlijk het meest bekende voorbeeld van een sorteeroptimalisatie die gebruik maakt van de functionele programmeerfaciliteiten van Perl, te gebruiken wanneer de sorteervolgorde van items afhankelijk is van een dure functie.
# 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;
Het probleem met het eerste voorbeeld is dat de comparator heel vaak wordt aangeroepen en waarden steeds opnieuw blijft berekenen met een langzame functie. Een typisch voorbeeld is het sorteren van bestandsnamen op bestandsgrootte:
use File::stat;
@sorted = sort { stat($a)->size <=> stat($b)->size } glob "*";
Dit werkt, maar in het beste geval kost het twee overheadaanvragen per vergelijking, in het slechtste geval moet het voor elke vergelijking twee keer naar de schijf gaan en die schijf bevindt zich mogelijk in een overbelaste bestandsserver aan de andere kant van de planeet.
Voer de truc van Randall Schwartz in.
De Schwartzian Transform duwt in feite @list
door drie functies, van onder naar boven. De eerste map
verandert elk item in een lijst met twee elementen van het oorspronkelijke item en het resultaat van de langzame functie als een sorteersleutel, dus aan het einde van dit element hebben we slow()
precies één keer voor elk element genoemd. De volgende sort
heeft dan eenvoudig toegang tot de sorteersleutel door in de lijst te kijken. Omdat we niet om de sorteersleutels geven, maar alleen de originele elementen in gesorteerde volgorde nodig hebben, gooit de laatste map
de lijsten met twee elementen weg uit de reeds gesorteerde lijst die het van @sort
ontvangt en retourneert een lijst met alleen hun eerste leden .
Hoofdletterongevoelig sorteren
De traditionele techniek om ervoor te sort
negeren zaak is om strings te geven lc
of uc
ter vergelijking:
@sorted = sort { lc($a) cmp lc($b) } @list;
Dit werkt op alle versies van Perl 5 en is volledig voldoende voor Engels; het maakt niet uit of u uc
of lc
. Het is echter een probleem voor talen als Grieks of Turks, waar er geen 1: 1-overeenkomst is tussen hoofdletters en kleine letters, zodat u verschillende resultaten krijgt, afhankelijk van of u uc
of lc
. Daarom heeft Perl 5.16 en hoger een case-vouwfunctie genaamd fc
die dit probleem voorkomt, dus moderne meertalige sortering zou dit moeten gebruiken:
@sorted = sort { fc($a) cmp fc($b) } @list;