Sortieralgorithmus
speedy
- perl
Hi Forumers,
gibt es eine Möglichkeit, die sort-Funktion in PERL so zu beeinflussen, daß sie String mit enthaltenen Zahlen richtig sortiert (also nach der Wertigkeit der Zahlen). Etwa nach folgendem Beispiel:
RAWLIST: name14, name1, name65, name100
SORTLIST: name1, name14, name65, name100
Vielen Dank für Eure Hilfe
speedy
Hallo!
gibt es eine Möglichkeit, die sort-Funktion in PERL so zu beeinflussen, daß sie String mit enthaltenen Zahlen richtig sortiert (also nach der Wertigkeit der Zahlen). Etwa nach folgendem Beispiel:
RAWLIST: name14, name1, name65, name100
SORTLIST: name1, name14, name65, name100
Soll das Prefix ("name") immer gleich sein?
In diesem Falle würde ich sprintf verwenden (z.B. $a = sprintf ("%03d", $a); ), um etwas in der Form name014, name015 zu erhalten.
Und dann kannst Du mit @sort_list = sort (@unsort_list); das ganze einfach sortieren. (ev. noch reverse anwenden, um die gewünschte Reihenfolge zu erhalten.)
Ist das Präfix nicht gleich, würde ich mit hashes arbeiten.
Felix
hi ho
@sortlist=sort {my $x=$a,$y=$b;$x=~s/\D*//;$y=~s/\D*//;$x<=>$y;} @rawlist
tut genau das, was du moechtest :-)
und zwar loescht er aus dem string alles bis zur ersten ziffer ($x=~s/\D*//)
und vergleicht dann die ziffern ($x<=>$y)
ich liebe einzeiler :-)
cua
n.d.p.
hi ho
@sortlist=sort {my $x=$a,$y=$b;$x=~s/\D*//;$y=~s/\D*//;$x<=>$y;} @rawlist
tut genau das, was du moechtest :-)
und zwar loescht er aus dem string alles bis zur ersten ziffer ($x=~s/\D*//)
und vergleicht dann die ziffern ($x<=>$y)ich liebe einzeiler :-)
;-)))) s.u.
Ich bin mir da nicht so sicher, daß Deine Lösung genau das Richtige tut ... Ich habe es zumindest so verstanden, daß die Strings nicht einfach ignoriert werden sollten:
@rawlist = qw(name7 name100 name7ort50 name7strasse name7abc name15hallo9 name100ok name7ort1000 name);
sollte wohl folgendes ergeben:
name
name7
name7abc
name7ort50
name7ort1000
name7strasse
name15hallo9
name100
name100ok
Mein Einzeiler dazu:
@sortlist=sort{my(@b,$r)=split'(\d+)',$b;for(split'(\d+)',$a){$r=/\d/?$_<=>shift@b :$_ cmp shift@b}$r-@b} @rawlist;
Ist ja recht grausam ... besser wäre da wohl:
-----------------------------------------------------------------------------
sub numbercmp {
# die split-Funktion erzeugt eine Liste, in
# der abwechselnd Texte und Zahlen auftreten
my (@b, $result, $a_part, $b_part) = split('(\d+)', $b);
#-----------------------------------------------
# Nun wird jeder Listenteil des Parameters $a
# mit dem entsprechenden Teil von $b verglichen
foreach $a_part (split('(\d+)', $a)) {
#----------------------------------------------------
# Der entsprechende Teil von $b wird besorgt, in dem
# das entprechende Array von vorne gekürzt wird
$b_part = shift(@b);
#--------------------------------------------------
# Sind die Teile Zahlen, dann mit <=> vergleichen.
# Sonst mit cmp
# Enthält $result schon einen Wert ungleich null,
# so ergab ein früherer Durchlauf ein Ergebnis.
# Dann muss nicht weiter verglichen werden (=)
if ($a_part =~ m/\d/) {
$result = $result $a_part <=> $b_part;
} else {
$result = $result $a_part cmp $b_part;
}
}
#-----------------------------------------------
# Ist hier $result noch null, dann waren bisher
# alle Vergleiche ergebnislos. Ist im Array zu
# $b noch Inhalt, so ist $a der kleinere
unless ($result) {
$result = -1 if @b;
}
return $result;
}
print join "\n", sort numbercmp @rawlist;
-----------------------------------------------------------------------------
Viel Spaß,
Jörk