【问题标题】:How can I sort a hash of hashes by key in Perl?如何在 Perl 中按键对散列进行排序?
【发布时间】:2010-10-19 02:16:00
【问题描述】:

我想对实际上具有哈希值的哈希进行排序。例如:

my %hash1=(
   field1=>"",
   field2=>"",
   count=>0,
);
my %hash2;
$hash2{"asd"}={%hash1};

我在%hash2 中插入了很多哈希值,%hash2 的计数值不同。

如何根据hash1的计数值对%hash1进行排序?

有没有办法在不手动实现快速排序的情况下做到这一点,例如使用 Perl 的排序功能?

【问题讨论】:

  • 您的意思是要从 hash2 中的值中获取按计数排序的哈希列表(如 hash1)?
  • yes Jagmal,这意味着我想对 $hash2{"asd"}{count} 进行排序。

标签: perl sorting hash


【解决方案1】:
my @hash1s = sort {$a->{count} <=> $b->{count}} values %hash2;

【讨论】:

  • 我尝试过这种方式,但收到以下警告:[警告]:在数值比较 () 中使用未初始化的值
  • 代码 sn-p 用于我的答案和我对您的答案的评论,在测试时对我有用(即使使用 -w 和“使用严格”)。
  • 您收到该警告是因为您的一个或多个哈希值对于“计数”键没有价值。如果你想把它们算为 0,你可以排序 {($a->{count} || 0) ($b->{count} ||0)} values %hash2;
  • 没有我所有的计数值都将 0 作为默认值。但是在我的生产代码中,键的名称不算是total_cnt,但是排序算法按升序排序,我需要按降序排序。
  • @holydiver:使用 $b->{count} $a->{count} 进行降序(即交换 a 和 b)。
【解决方案2】:

如果您想从 hash2 中的值中获取按计数排序的哈希列表(如 hash1),这可能会有所帮助:

@sorted_hash1_list = sort sort_hash_by_count_key($a, $b) (values (%hash2);


# This method can have any logic you want
sub sort_hash_by_count_key {
    my ($a, $b) = @_;
    return $a->{count} <=> $b->{count};
}

【讨论】:

  • 你的意思是说“sort \&sort_hash_by_count_key, values %hash2”而不是你现在拥有的?
【解决方案3】:

请参阅http://perldoc.perl.org/functions/sort.html 了解有关 Perl 中排序如何工作的大量上下文。

这是一个例子 .. 试图可读,而不是腐烂。

#!/usr/bin/perl
# Sort Hash of Hashes by sub-hash's element count.
use warnings;
use strict;


my $hash= {
            A=>{C=>"D",0=>"r",T=>"q"}
           ,B=>{}
           ,C=>{E=>"F",G=>"H"}
          };

sub compareHashKeys {0+(keys %{$hash->{$a}}) <=> 0+(keys %{$hash->{$b}}) }

my @SortedKeys = sort compareHashKeys keys %{$hash};
print join ("," , @SortedKeys) ."\n";

【讨论】:

  • 0+ 应该将值强制转换为数字,但是, 已经这样做了,所以 0+ 确实是多余的。 :-P
  • 嗯,从 cmp 或 出来的值已经是数字了,是 -1、0 或 1。数据是什么并不重要。 sort() 需要 -1、0 或 1 来决定如何排序。
  • 正如 Chris 指出的那样,我将 0+ 放在那里以将键数组强制转换为标量(从而保持数组的长度)。显然 已经这样做了.. 我将继续这样做,因为它让我很清楚,当重新阅读代码时,预期会发生什么。 YMMD
【解决方案4】:

来自perlfaq4"http://faq.perl.org/perlfaq4.html#How_do_I_sort_a_hash" 的答案包含您编写代码所需的大部分信息。

您可能还想查看Learning Perl 中的排序章节。

克里斯有一个完全好的答案,虽然我讨厌这样使用values。做同样事情的更熟悉的方法是遍历顶级哈希的键,但按二级键排序:

my @sorted_hashes = 
    sort { $hash2->{$a}{count} <=> $hash2->{$b}{count} } 
    keys %hash2;

我这样做是因为它不那么令人费解。


如何对散列进行排序(可选择按值而不是键)?

(由布赖恩·d·福伊提供)

要对哈希进行排序,请从键开始。在此示例中,我们将键列表提供给排序函数,然后按 ASCII 顺序比较它们(这可能会受到您的语言环境设置的影响)。输出列表具有按 ASCII 顺序排列的键。一旦我们有了密钥,我们就可以通过它们来创建一个报告,以 ASCII 顺序列出密钥。

my @keys = sort { $a cmp $b } keys %hash;

foreach my $key ( @keys )
    {
    printf "%-20s %6d\n", $key, $hash{$key};
    }

不过,我们可以在 sort() 块中获得更多花哨。我们可以用它们计算一个值并将该值用作比较,而不是比较键。

例如,为了使我们的报告顺序不区分大小写,我们在双引号字符串中使用 \L 序列将所有内容变为小写。然后 sort() 块比较小写的值以确定放置键的顺序。

my @keys = sort { "\L$a" cmp "\L$b" } keys %hash;

注意:如果计算量很大或哈希有很多元素,您可能需要查看 Schwartzian 变换来缓存计算结果。

如果我们想按哈希值排序,我们使用哈希键来查找它。我们仍然会得到一个键列表,但这次它们是按值排序的。

my @keys = sort { $hash{$a} <=> $hash{$b} } keys %hash;

从那里我们可以变得更复杂。如果哈希值相同,我们可以对哈希键进行二次排序。

my @keys = sort {
    $hash{$a} <=> $hash{$b}
        or
    "\L$a" cmp "\L$b"
    } keys %hash;

【讨论】:

    【解决方案5】:

    按数字排序使用 和字符串使用 cmp。

    # sort by the numeric count field on inner hash
    #
    foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) {
       print $key,$hash2{$key}->{'count'},"\n";
    }
    
    # sort by the string field1 (or field2) on the inner hash
    #
    foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) {
       print $key,$hash2{$key}->{'field1'},"\n";
    }
    

    要颠倒顺序,只需交换 $a 和 $b:

    # sort by the numeric count field on inner hash
    #
    foreach my $key (sort {$hash2{$a}->{'count'} <=> $hash2{$b}->{'count'}} keys %hash2) {
       print $key,$hash2{$key}->{'count'},"\n";
    }
    
    # sort by the string field1 (or field2) on the inner hash
    #
    foreach my $key (sort {$hash2{$a}->{'field1'} cmp $hash2{$b}->{'field1'}} keys %hash2) {
       print $key,$hash2{$key}->{'field1'},"\n";
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-07
      • 2018-03-03
      • 2011-12-13
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 2014-11-07
      • 2012-10-09
      相关资源
      最近更新 更多