2011-08-19 69 views
5

我相信这是你会怎么通常由值排序的哈希:排序按值散列当它有许多键

foreach my $key (sort { $hash{$a} <=> $hash{$b} } (keys %hash)) { 
    print "$key=>$hash{$key}"; 
} 

这将打印出最小到最大的价值。

现在,如果我有这样的哈希:

$hash{$somekey}{$somekey2}{$thirdkey} 

我排序的价值观和如何能得到所有的钥匙呢?

+0

所以,你想排序结构内的深度,而不管深度? – DavidO

+0

这个散列中有3个键的固定深度,我想按照存在的所有键的三元组的值排序散列。 – petranaya

回答

3

我只是想创建一个新的哈希:

my %new; 
for my $k1 (keys %hash) { 
    for my $k2 (keys %{$hash{$k1}}) { 
    for my $k3 (keys %{$hash{$k1}{$k2}}) { 
     $new{$k1,$k2,$k3} = $hash{$k1}{$k2}{$k3}; 
    } 
    } 
} 

my @ordered = sort { $new{$a} <=> $new{$b} } keys %new; 
for my $k (@ordered) { 
    my @keys = split($;, $k); 
    print "key: @k  - value: $new{$k}\n"; 
} 
+0

谢谢,我刚刚用完了。 – petranaya

+2

请注意'$;'必须是一个值,*永远不会出现在您的按键中*(它默认为“\ x1c”,一个控制字符),否则此代码会崩溃并烧毁。 – hobbs

+0

@FMc - 谢谢!后更正。 – ErikR

1

这里是一种使用Deep::Hash::Utils做到这一点。

use Deep::Hash::Utils qw(slurp); 

my %h = (
    A => { 
     Aa => { Aaa => 4, Aab => 5 }, 
     Ab => { Aba => 1 }, 
     Ac => { Aca => 2, Acb => 9, Acc => 0 }, 
    }, 
    B => { 
     Ba => { Baa => 44, Bab => -55 }, 
     Bc => { Bca => 22, Bcb => 99, Bcc => 100 }, 
    }, 
); 

my @all_keys_and_vals = slurp \%h; 
print "@$_\n" for sort { $a->[-1] <=> $b->[-1] } @all_keys_and_vals; 

输出:

B Ba Bab -55 
A Ac Acc 0 
A Ab Aba 1 
A Ac Aca 2 
A Aa Aaa 4 
A Aa Aab 5 
A Ac Acb 9 
B Bc Bca 22 
B Ba Baa 44 
B Bc Bcb 99 
B Bc Bcc 100 
1

我已经做了通过移动参考升降到合适的哈希键类似的东西。然后你可以在指针上进行排序。

这样做的好处是,如果级别改变,很容易调整。

我已经使用过这种方法,通过引用一组键来系统地将指针移动到特定的级别。 (例如:我的@Keys =('Value','Value2');)

我相信下面的例子的派生可能会给你你正在寻找的。

my $list_ref; 
my $pointer; 

my %list = (
    Value => { 
     Value2 => { 
     A => '1', 
     C => '3', 
     B => '2', 
     }, 
    }, 
); 

$list_ref = \%list; 
$pointer = $list_ref->{Value}->{Value2}; 

foreach my $key (sort { $pointer->{$a} <=> $pointer->{$b} } (keys %{$pointer})) { 
    print "Key: $key\n"; 
} 
1

学术目的,这里是一个相当整齐递归函数:

sub flatten_hash { 
    my ($hash, $path) = @_; 
    $path = [] unless defined $path; 

    my @ret; 

    while (my ($key, $value) = each %$hash) { 
    if (ref $value eq 'HASH') { 
     push @ret, flatten_hash($value, [ @$path, $key ]); 
    } else { 
     push @ret, [ [ @$path, $key ], $value ]; 
    } 
    } 

    return @ret; 
} 

这需要像

{ 
    roman => { 
     i => 1, 
     ii => 2, 
     iii => 3, 
    }, 
    english => { 
     one => 1, 
     two => 2, 
     three => 3, 
    }, 
} 

散列函数,并把它变成像

(
    [ ['roman','i'], 1 ], 
    [ ['roman', 'ii'], 2 ], 
    [ ['roman', 'iii'], 3 ], 
    [ ['english', 'one'], 1 ], 
    [ ['english', 'two'], 2 ], 
    [ ['english', 'three'], 3 ] 
) 
列表

尽管当然t他的命令必然会有所不同。鉴于该列表,您可以将其排序在{ $a->[1] <=> $b->[1] }或类似的位置,然后从每个条目的@{ $entry->[0] }中提取关键路径。无论数据结构的深度如何,即使叶节点不会全部出现在同一深度,它也可以工作。不过,它需要一点点的扩展来处理并非纯粹使用hashrefs和纯标量的结构。