2010-07-08 33 views
2
my %data (
    KEY1 => { 
     SUBKEY1 => "Canada", 
     SUBKEY3 => "75.00", 
     SUBKEY2 => "50.00",  
    }, 
    KEY3 => { 
     SUBKEY2 => "150.00", 
    }, 
    KEY2 => { 
     SUBKEY3 => "200.00", 
     SUBKEY1 => "Mexico", 
}, 
); 

如何打印按鍵名排序的列表以及按子鍵名排序的每個鍵名?然後按子鍵排序 - 如果子鍵undef設置爲空字符串

這裏是我想打印什麼: (請注意,如果沒有定義的子項,用一個空字符串的子項的佔位符存在)

KEY1: SUBKEY1 is "Canada" 
KEY1: SUBKEY2 is "50.00" 
KEY1: SUBKEY3 is "75.00" 
KEY2: SUBKEY1 is '' 
KEY2: SUBKEY2 is "150.00" 
KEY2: SUBKEY3 is '' 
KEY3: SUBKEY1 is "Mexico" 
KEY3: SUBKEY2 is '' 
KEY3: SUBKEY3 is "200.00" 
+0

墨西哥在'$ data {KEY2}'中,但與您期望的輸出中的'KEY3'相關聯。 – 2010-07-08 19:29:15

回答

3
use strict; 
use warnings; 

my %data = (
    KEY1 => { 
     SUBKEY1 => "Canada", 
     SUBKEY3 => "75.00", 
     SUBKEY2 => "50.00",  
    }, 
    KEY3 => { 
     SUBKEY2 => "150.00", 
    }, 
    KEY2 => { 
     SUBKEY3 => "200.00", 
     SUBKEY1 => "Mexico", 
}, 
); 

my %all_sub_keys; 
for my $sub_hash (values %data){ 
    $all_sub_keys{$_} ++ for keys %$sub_hash; 
} 

my @all_sub_keys = sort keys %all_sub_keys; 

for my $k (sort keys %data){ 
    for my $sk (@all_sub_keys){ 
     my $val = exists $data{$k}{$sk} ? $data{$k}{$sk} : '--'; 
     print join(' ', $k, $sk, $val), "\n"; 
    } 
} 
2

我假設提前知道一組子鍵。

#!/usr/bin/perl 

use strict; use warnings; 

my %data = (
    KEY1 => { 
     SUBKEY1 => "Canada", 
     SUBKEY3 => "75.00", 
     SUBKEY2 => "50.00", 
    }, 
    KEY3 => { 
     SUBKEY2 => "150.00", 
    }, 
    KEY2 => { 
     SUBKEY3 => "200.00", 
     SUBKEY1 => "Mexico", 
}, 
); 

my @subkeys = qw(SUBKEY1 SUBKEY2 SUBKEY3); 

for my $key (sort keys %data) { 
    my %sub = map { 
     my $v = $data{$key}{$_}; 
     $_ => defined($v) ? $v : ''; 
    } @subkeys; 

    for my $subkey (@subkeys) { 
     print "$key $subkey $sub{$subkey}\n"; 
    } 
} 

輸出:

KEY1 SUBKEY1 Canada 
KEY1 SUBKEY2 50.00 
KEY1 SUBKEY3 75.00 
KEY2 SUBKEY1 Mexico 
KEY2 SUBKEY2 
KEY2 SUBKEY3 200.00 
KEY3 SUBKEY1 
KEY3 SUBKEY2 150.00 
KEY3 SUBKEY3
3

怎麼樣Schwartzian transform

#! /usr/bin/perl 

use 5.10.0; # for // (aka defined-or) 
use warnings; 
use strict; 

my %data = ...; 

# get all subkeys used in %data 
my @subkeys = keys %{ 
    { map { map +($_ => 1), 
      keys %{ $data{$_} } } 
    keys %data 
    } 
}; 

print map qq|$_->[0]: $_->[1] is "$_->[2]"\n|, 
     sort { $a->[0] cmp $b->[0] 
        || 
      $a->[1] cmp $b->[1] } 
     map { my $key = $_; 
      map [ $key, $_, $data{$key}{$_} // "" ] => 
      @subkeys } 
     keys %data; 

記得閱讀Schwartzian從後到前的變換。第一個最接近結尾的是map將某個未指定順序的記錄列表展平或「非規範化」爲%data。嵌套0​​是達到子項所必需的。要處理任意深度的嵌套,請遞歸定義flatten

我們做了一個較早的傳遞來收集所有使用的子鍵,所以如果某個子鍵不存在,$data{$key}{$_}的值就是未定義的值。使用//,版本5.10.0中定義的或新的操作符指定默認值""

與以下形式的扁平記錄

[ "KEY1", "SUBKEY3", "75.00" ], 
[ "KEY1", "SUBKEY1", "Canada" ], 
... 

排序是直接的:比較所述相應的第一元件(鍵),並且如果這些是相等的,回落到秒(子密鑰)。

最後,最外面的map格式化現在排序的非規格化輸出記錄,結果列表通過print運算符轉到標準輸出。

輸出:

KEY1: SUBKEY1 is "Canada" 
KEY1: SUBKEY2 is "50.00" 
KEY1: SUBKEY3 is "75.00" 
KEY2: SUBKEY1 is "Mexico" 
KEY2: SUBKEY2 is "" 
KEY2: SUBKEY3 is "200.00" 
KEY3: SUBKEY1 is "" 
KEY3: SUBKEY2 is "150.00" 
KEY3: SUBKEY3 is ""

要與每個相應的鍵相同的線組的子項,去與代碼如

my @subkeys = sort keys %{ ... ; 

foreach my $key (sort keys %data) { 
    my @values; 
    foreach my $subkey (@subkeys) { 
    my $value = $data{$key}{$subkey} // ""; 
    push @values => qq|$subkey is "$value"|; 
    } 

    local $" = ", "; 
    print "$key: @values\n"; 
} 

你可以在一個實用的風格寫,但結果是泥濘一團糟:

print map { my $key = $_; 
      "$key: " . 
       join(", " => 
       map { my $value = $data{$key}{$_} // ""; 
         qq|$_ is "$value"| 
        } 
       @subkeys) . 
      "\n" 
      } 
     sort keys %data; 

輸出:

KEY1: SUBKEY1 is "Canada", SUBKEY2 is "50.00", SUBKEY3 is "75.00" 
KEY2: SUBKEY1 is "Mexico", SUBKEY2 is "", SUBKEY3 is "200.00" 
KEY3: SUBKEY1 is "", SUBKEY2 is "150.00", SUBKEY3 is ""
+0

謝謝,我一直在研究這種方法,但直到你發佈這個例子,我才掌握語法...非常好! – 2010-07-08 21:39:35

+0

這條線是做什麼的? map [$ key,$ _,$ data {$ key} {$ _} //「」] => – 2010-07-08 23:43:04

+0

@cgmojoco謝謝,我很高興它有幫助!查看更新的答案。 – 2010-07-09 01:15:22