linux - How do I sort alphanumerical keys in Perl? -
i have hash keys aa00, aa01, ab00, ab23, za03, zb45, aa02, da05, aa45, de67, de84, zz99 , need sort them first letter set number minor major.
edit: case more complex indeed. letters must read left right , number of digits , letter might change. is, a00 must before aa00 , ab00. b00 must after az99 before ba00.
also, if find aa, aaa, aab , aaaa, aaa, aab shall considered subset goes before aa, , aaaa shall before triple letter subset. abaa, example, must after aa.
numbers in linear order, 0 before 1, , 1 before 99, there no limit number of digits. 1 might represented 1 or 01 (see zb). ignore spaces, there maintain columns.
that is,
a 00, aaaa00, aaa 00, aab 00, aa 00, aa 01, aa 02, aa 45, abaa00, ab 00, (first letter change) ab 23, az 99, b 00, ba 00, da 05, (second letter change, first letter restarts a) de 67, de 84, za 03, zb 45, zb 145, zb1145, zz 99,
i tried classical
for $key ( sort {$a<=>$b} keys %hash) { print "($key)->($hash{$key})\n"; }
but no sorting produced @ all. indeed, keys passed totally disorganzied.
there logic used produced data set. used:
while (certain thing true) { select $letter; $identifier .= $letter }
it supposed first letter represents set a, second letter represents subset in a. is, if hava aa, ab , ac, a, b , c subsets in a. if had abc, c subset in subset b of set a. if had, then, abca, last subset in c.
my @sorted = map $_->[0], sort { $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] } map { ($l, $n) = /^([a-z]+)([0-9]{1,9})\z/ or die("unexpected data"); $l .= "\xff" if length($l) > 1; [ $_, $l, $n ] } @unsorted;
optimized:
my @sorted = map { unpack('j/a*', scalar(reverse($_))) } sort map { ($l, $n) = /^([a-z]+)([0-9]{1,9})\z/ or die("unexpected data"); pack('a* a* j>', $l, length($l) == 1 ? "\x00" : "\xff", $n) . reverse(pack('j/a*', $_)) } @unsorted;
note: may possible handle larger numbers without changing check, depending on build of perl.
Comments
Post a Comment