我有一个哈希,其键看起来像AA00,AA01,AB00,AB23,ZA03,ZB45,AA02,DA05,AA45,DE67,DE84,ZZ99,我需要先按字母设置然后按照次要编号对它们进行排序到专业。
编辑:案件确实更复杂。必须从左到右阅读字母,并且数字和字母的数量可能会改变。也就是说,A00必须在AA00和AB00之前。 B00必须在AZ99之后但在BA00之前。
此外,如果我找到AA,AAA,AAB和AAAA,则AAA,AAB应被视为AA之前的子集,AAAA应位于三字母子集之前。但是,ABAA必须在AA之后。
数字是线性顺序,即0在1之前,1在99之前,但是数字没有限制。 1可以用1或01表示(见ZB)。忽略空格,它们用于维护列。
即,
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 as A)
DE 67,
DE 84,
ZA 03,
ZB 45,
ZB 145,
ZB1145,
ZZ 99,
我尝试了经典
for $key ( sort {$a<=>$b} keys %hash) {
print "($key)->($hash{$key})\n";
}
但根本没有产生任何分类。确实,钥匙完全没有通过。
有用于生成数据集的逻辑。他们使用了:
While (Certain thing is True) {
Select a $letter;
$identifier .= $letter
}
假设第一个字母是a表示集合A,第二个字母表示A中的子集。也就是说,如果我有AA,AB和AC,则A,B和C是A中的子集。我有ABC,C是集合A的子集B中的一个子集。如果我有,那么,ABCA,最后一个A是C中的一个子集。
答案 0 :(得分:4)
my @sorted =
map $_->[0],
sort {
$a->[1] cmp $b->[1]
||
$a->[2] <=> $b->[2]
}
map {
my ($l, $n) = /^([A-Z]+)([0-9]{1,9})\z/
or die("Unexpected data");
$l .= "\xFF" if length($l) > 1;
[ $_, $l, $n ]
}
@unsorted;
优化
my @sorted =
map { unpack('J/a*', scalar(reverse($_))) }
sort
map {
my ($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;
注意:除了检查之外,可以处理更大的数字而不更改任何内容,具体取决于您的Perl构建。
答案 1 :(得分:-2)
正如一些海报所写,问题并不完全清楚。尽管如此,我的解决方案尝试如下。我没有测试过这段代码,所以你可能需要稍微调整一下才能使它工作。
my @sorted_keys = sort by_letters_then_numbers keys %hash;
sub by_letters_then_numbers
{
if ($a !~ /^([a-zA-Z]+)\s*(\d+)$/) {return 0};
my $a_letters = $1;
my $a_number = $2;
if ($b !~ /^([a-zA-Z]+)\s*(\d+)$/) {return 0};
my $b_letters = $1;
my $b_number = $2;
return(($a_letters cmp $b_letters) || ($a_number <=> $b_number));
}