SortierenPerl

SeitenanfangSeitenendesort

Wie bereits bekannt sein sollte, werden Arrays mit Hilfe des sort-Befehls sortiert. Jedoch geschieht dies auf der Basis von alphanumerischer Sortierung; d. h. Zahlen werden wie Strings behandelt, was bewirkt dass 17 kleiner ist als 9.

@z=(1..20);
print join(", ", sort(@z));
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, 3, 4, 5, 6, 7, 8, 9

SeitenanfangSeitenendeSortieren von Zahlen

Was wäre Perl, wenn man obiges Problem nicht beseitigen könnte?

Die Lösung lautet ganz einfach: Man sagt Perl, wie es sortieren soll: Man schreibt nach dem sort-Befehl und vor dem zu sortierenden Array in geschweiften Klammern die Sortieranweisung:

@z=(1..20);
print join(", ", sort{$a<=>$b}(@z));
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

Das fällt auf:

Analog zu <=> arbeitet cmp bei Strings.

SeitenanfangSeitenendeSortiervorschrift angeben

Perl vergleicht also $a mit $b und möchte als Ergebnis 1, 0 oder -1 erhalten. Falls 1 zurückgegeben wird, dann war $a größer, falls 0 zuurückgegeben wird, war $a und $b gleich, falls -1 zurückgegeben wird, war $b größer. Genauer gesagt interpretiert Perl die Rückgabewerte folgendermaßen: eine Zahl größer oder gleich 1 für größer, eine Zahl zwischen -1 und 1 (ausschließlich 1 und -1) für gleich und eine Zahl kleiner gleich -1 für kleiner.

Im obigen Abschnitt haben wir bereits eine Sortiervorschrift angegeben. Diese kann man beliebig gestalten - sie muss eben nur Zahlen wie 1, 0 oder -1 zurückgeben:

@worte=("Auto", "abnehmen", "ADAC", "Abfindung", "andauern");

print "normal:     ".(join " - ", sort @worte)."\n";
print "UPPERCASE:  ".(join " - ", sort{"\U$a" cmp "\U$b"}@worte)."\n";
print "3rd Letter: ".(join " - ", sort{substr($a,2,1) cmp substr($b,2,1)}@worte);
normal:     ADAC - Abfindung - Auto - abnehmen - andauern
UPPERCASE:  Abfindung - abnehmen - ADAC - andauern - Auto
3rd Letter: ADAC - andauern - Abfindung - abnehmen - Auto

SeitenanfangSeitenendeSortiervorschrift als Funktion angeben

Man kann die Sortiervorschrift auch als Funktion formulieren. Das sieht dann so aus:

@z=(1..20);
print join(", ", sort{&sortNumbers}(@z))."\n";
print join(", ", sort sortNumbers @z)."\n";
print join(", ", sort{&sortNumbers2}(@z))."\n";


sub sortNumbers() {
  $a<=>$b;
}

sub sortNumbers2() {
  if ($a < $b) { -1; }
  elsif ($a==$b) { 0; }
  else { 1; }
}
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

Statt den Code in die geschweiften Klammern zu schreiben, wird dieser in einer extra Funktion angegeben. Auch hier werden die vordefinierten Variablen $a und $b benutzt. Man kann sich so eine spezielle Funktion für Sortierung erstellen und sie immer wieder verwenden.

SeitenanfangSeitenendeSortieren der Zeilen einer Matrix

Im folgenden Beispiel soll eine Matrix nach Zeilen sortiert werden. Es wird davon ausgegangen, dass die Matrix nur Zahlen enthält und dass alle Zeilen gleich lang sind. Eine Zeile ist größer als die andere, falls es einen Eintrag in der einen Zeile gibt, der größer ist als der Eintrag an der gleichen Position der anderen Zeile. Vor dieser Position müssen alle gleich sein. Zwei Zeilen sind gleich, falls alle Einträge gleich sind. Eine Zeile ist kleiner als die andere Zeile, falls die andere Zeile größer ist als die eine.

@A=( [1, 2, 3, 4],
     [5, 6, 7, 8],
     [9, 0, 1, 2] );

#sortieren
@sortedA = sort{&arraySortDown}@A;

# Ausgabe
foreach (@sortedA) { print join(", ", @$_)."\n"; }


#Sortierfunktion
sub arraySortDown{
  my $my_cmp=0;
  for (my $i=0; $i<=$#$a; $i++) {
    if ($my_cmp=$$b[$i]<=>$$a[$i]) { last; }
  }
  $my_cmp;
}
9, 0, 1, 2
5, 6, 7, 8
1, 2, 3, 4

Das fällt auf:


Seitenanfang FehlermeldungHilfe zur Fehlermeldung © 2001-2003 Email an den AutorPerl, Lehrstuhl Mathe II, Uni Bayreuth