如何对perl哈希键进行排序

时间:2014-09-16 12:16:59

标签: perl sorting hash

我有一个看起来像这样的哈希

my %hash = (
    '124:8' => '',
    '4:2'   => '',
    '17:11' => '',
    '17:0'  => '',
    #and so on
);

我尝试排序并使用小数字到更大的哈希键

for my $keys ( sort { $a > $b } keys %hash ) {
    #do stuff
}

这给了我一些看似正确的结果,但有时会失败。我不知道如何将这两个数字124:84:2进行比较,因为它中间有:,有什么建议吗?

3 个答案:

答案 0 :(得分:4)

对数字进行排序时,使用<=>运算符:

for my $key (sort { $a <=> $b } keys %hash) {

此运算符根据比较返回1,0或-1。 >只返回true或false,这解释了它使用了一些结果,但不是全部。

由于您的密钥不是数字,因此它们只会部分转换为数字,您将收到警告

Argument "17:11" isn't numeric in sort

然后你需要使用类似Sort::Key::Natural的东西,或者摆动自己的东西,例如:

sort {
    my @a = $a =~ /\d+/g;
    my @b = $b =~ /\d+/g;
    $a[0] <=> $b[0] ||
    $a[1] <=> $b[1]    # continue as long as needed
} keys %hash

您也可以使用Schwartzian transform来缓存数字,并可能加快排序速度。

或者只是按字符串比较排序,但这会导致17:1117:2之后结束。

答案 1 :(得分:4)

您可能希望对按:

分隔的第一个和第二个数字进行排序
my @sorted = sort {
  my ($aa, $bb) =  map [ split /:/ ], $a, $b;
  $aa->[0] <=> $bb->[0] || $aa->[1] <=> $bb->[1]

} keys %hash;

for my $key (@sorted) { .. }

使用Schwartzian,

my @sorted = map $_->[0],
sort {
  $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2]
}
map [ $_, split /:/ ],
keys %hash;

答案 2 :(得分:0)

不如上述解决方案那么优雅,但是将:转换为.并将它们作为浮点数进行比较的内容是什么?因为没有数学运算,所以没有舍入错误,下一个可以工作:

my %tmp = map { (my $x = $_) =~ s/:/./; $_,$x} keys %hash;
my @sortedkeys =  sort { $tmp{$a} <=> $tmp{$b} } keys %tmp;
#4:2 17:0 17:11 124:8

或者这种做法是错误的?