【问题标题】:How to sort perl hash keys [duplicate]如何对perl哈希键进行排序[重复]
【发布时间】:2014-09-16 23:02:58
【问题描述】:

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

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,因为中间有 :,有什么建议吗?

【问题讨论】:

标签: perl sorting hash


【解决方案1】:

您可能希望对由: 分隔的第一个和第二个数字进行排序

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】:

    在对数字进行排序时,使用&lt;=&gt; 运算符:

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

    此运算符根据比较返回 1、0 或 -1。 &gt; 只返回 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 之后结束。

    【讨论】:

    • 哎呀,这太棒了,但仍然有一个错误,它在17:0之前打印17:11
    • 那是因为那些是字符串而不是数字。它们被 Perl 转换为数字,都变成 17。你需要将数字部分分开,或者使用自然排序模块。
    【解决方案3】:

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

    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
    

    还是这种做法不对?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 2016-04-22
      • 2015-03-12
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多