2013-06-19 66 views
2

如何根據鍵值對多級Perl哈希進行排序(並打印)?對多級Perl哈希進行排序(動態基於算術)

%hash = (
    a => { k1 => 51, k2 => 52, k3 => 53 }, 
    b => { k1 => 61, k2 => 62, k3 => 63 }, 
    c => { k1 => 71, k2 => 72, k3 => 73 }, 
) 

例如,根據k2的值對數值進行上述散列排序? 所以應該打印:

52,62,72 

我想知道我怎麼能擴大分揀單級哈希使用

sort { $hash{$b} <=> $hash{$a} } keys %hash` 

編輯

如果我有另外一個哈希

到多電平
my %property = (a => 7, b => 6, c => 5) 

我可以對%hash基於的$hash{key}{k2} * $property{key} 數值使用

#!/usr/bin/perl 
use strict; 
use warnings; 

my %hash = (
    a => { k1 => 51, k2 => 52, k3 => 53 }, 
    b => { k1 => 61, k2 => 62, k3 => 63 }, 
    c => { k1 => 71, k2 => 72, k3 => 73 }, 
); 

my %property = (a => 7, b => 6, c => 5); 


foreach (sort { ($hash{$a}{'k2'}*$property{$a}) <=> 
       ($hash{$b}{'k2'}*$property{$b}) } keys %hash) 
{ 
    printf("[%d][%d][%d]\n", 
    $hash{$_}{'k2'},$property{$_},$hash{$_}{'k2'}*$property{$_}); 
} 

結果應該是

72,52,62 as products are (360(72*5),364(52*7),372(62*6)) 
+0

你想的'k2'值進行排序('52,62,72')按字母順序通過第一級關鍵字('a,b,c'),還是你想對所有'k2'值進行數字排序? – amon

+0

[你有什麼嘗試?](http://whathaveyoutried.com) – 2013-06-19 16:26:07

+0

增加了一個額外的問題 – Jean

回答

1

這個程序會爲你問問。它首先列出按其值排序的k2元素的值,然後按其產品排序的相同元素與%property散列的相應元素進行排序。

請注意,您的期望輸出52,72,62是錯誤的。該產品是,如你所說,a => 364, b => 372, c => 360所以值應在訂貨c, a, b72, 52, 62

use strict; 
use warnings; 

my %hash = (
    a => { k1 => 51, k2 => 52, k3 => 53 }, 
    b => { k1 => 61, k2 => 62, k3 => 63 }, 
    c => { k1 => 71, k2 => 72, k3 => 73 }, 
); 

my %property = (a => 7, b => 6, c => 5); 

print join ',', map { $hash{$_}{k2} } sort { 
    my ($aa, $bb) = map { $hash{$_}{k2} } $a, $b; 
    $aa <=> $bb; 
} keys %hash; 
print "\n"; 

print join ',', map { $hash{$_}{k2} } sort { 
    my ($aa, $bb) = map { $hash{$_}{k2} * $property{$_} } $a, $b; 
    $aa <=> $bb; 
} keys %hash; 
print "\n"; 

輸出

52,62,72 
72,52,62 
+0

'sort {hash {$ b} {k2} * $ propery {$ b} <=> $ hash {$ a} {k2} * $ property {$ a}} keys%hash'似乎正在工作。這種方法有什麼缺陷嗎? – Jean

+0

@Jean:除了違反[* DRY *(不要重複自己)](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)開發原則外,沒有任何限制。如果您手動複製任何內容,則有可能複製件與原件不一致。您的評論是一個很好的例子! – Borodin

+0

我不清楚這裏有什麼重複? '$ a/$ b'? – Jean

3
sort {$hash{$a}{'k2'} <=> $hash{$b}{'k2'}} keys %hash 

宇宙飛船操作數值的左手側與右手側進行比較。這是最常見的最簡單的情況,與

$a <=> $b 

但在這種情況下,你想要比較哈希值,也可以做到這一點。

+0

我會用特殊的' - >'運算符:'sort $ hash {$ a} - > {k2} <=> $ hash {$ b} - > {k2} keys%hash;'。它更容易閱讀 - 特別是如果OP將向散列添加另一個散列。 –

3

獲取所有值在散列表:

values %hash; 

變換hashrefs的列表中k2項的內容:

map $_->{k2}, @list 

哦,跳過它,如果它是undef /沒有按不存在:

map $_->{k2} //(), @list 

數字排序列表:

sort { $a <=> $b } @list 

連接點:

sort { $a <=> $b } map { $_->{k2} //() } values %hash; 
+0

我這時候已經很晚了:) –

+0

@mpapec Nah,你提到'join',我忘記了。我們的答案是互補的 – amon

1
print join ",", sort { $a <=> $b } map { $_->{k2} } values %hash; 
-1

圍棋與ysth's答案,但此語法可能讓事情進行排序比較容易理解:

sort { $hash{$a}->{k2} <=> $hash{$b}->{k2} } keys %hash; 

請記住,$a$b是由排序隨機分配的散列鍵。您不知道分配給$a的密鑰或分配給$b的密鑰。在一次$a = "k1"和另一次$b = "k1"。你甚至不知道進行比較的次數。你所知道的是,$a$b被分配給你的散列中的鍵的值,你的工作是比較這兩個鍵來得到你想要的結果。

這是行不通的:

sort { $hash{$a}->{k2} * $property{$a} <=> $hash{$b}->{k2} * $property{$b} } keys %hash; 

因爲$a$b將被分配值​​,k2,或k3。您的%property散列中沒有這些密鑰。你可能會得到一堆警告。

如果你的排序算法比簡單的一個班輪更復雜,你會怎麼做?你可以指定一個子程序來爲你排序。

例如,您不希望對k2進行排序,而是希望對散列中所有值的總和進行排序。這是$hash{a}->{k1} + $hash{a}->{k2} + $hash->{k3}...$hash{c}->{k1} + $hash{c}->{k2}...,我不知道什麼是鑰匙。這個子程序會發現在%{ hash{$a} }所有鍵和添加他們,並在%{ hash{$b} }比較與所有鍵:

sort sort_function keys %hash; 

sub sort_function { 

    # Sum of all the values in the hash %{ $hash{$a} } 
    my $sum_a = 0; 
    for my $hash_key (keys %$hash{$a}) { 
     $sum_a += $hash{$a}->{$hash_key}; 
    } 
    # Sum of all the values in the hash %{ $hash{$b} } 
    my $sum_b = 0; 
    for my $hash_key (keys %$hash{$b}) { 
     $sum_b += $hash{$b}->{$hash_key}; 
    } 
    return $sum_a <=> $sum_b; 
} 
+0

它似乎在工作,雖然 – Jean

+2

'ysth'沒有發佈答案。你的意思是'YatesCM'?如果是這樣,那麼你所做的就是添加不必要的' - >'間接運算符,我認爲這些運算符很嘈雜,不那麼清楚。另外,當你說'%hash'的鍵實際上是'a'時''k3''''''與'%property'的鍵相同,所以你說的排序語句將不會工作是絕對好的。 – Borodin