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;


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow