2011-08-19 50 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和純標量的結構。