2016-07-26 63 views
0

我想從哈希引用生成數組,通過加入排序所有的哈希鍵來創建數組。 考慮我有動態哈希參考像從參考哈希產生數組

my $hash_ref = { 
      'A1' => { 
        'B2' => { 
          'C1' => { 
            'D1' => {}, 
            'D2' => {}, 
            'D3' => {} 
           } 
         }, 
        'B3' => { 
          'C1' => { 
            'D2' => {}, 
            'D1' => {}, 
            'D3' => {} 
           } 
         }, 
        'B1' => { 
          'C1' => { 
            'D1' => {}, 
            'D2' => {} 
           } 
         } 
       } 
     }; 

如何從上述散列創建陣列等

@arr = qw/A1B1C1D1 A1B1C1D2 A1B2C1D1 ..../;

下面

是我嘗試的代碼(其是不工作)

my $out = hash_walk($hash_ref); 

say Dumper $out; 

sub hash_walk { 
    my $hash = shift; 
    my $array_ref; 
    my $temp_arr; 
    my @temp_arr2; 
    foreach my $k (sort keys %$hash) { 
     $v = $$hash{$k}; 

     if (ref($v) eq 'HASH') { 

      # Recurse. 
      $temp_arr = hash_walk($v); 

     } 
     push @$array_ref, $k if $k; 

     my (@lvlfirst, @lvlnext); 

     if ($array_ref && $temp_arr){ 
      @lvlfirst = @$array_ref; 
      @lvlnext = @$temp_arr; 
     } 

     for (my $i = 0 ; $i <= $#lvlfirst ; $i++) { 
      for (my $j = 0 ; $j <= $#lvlnext ; $j++) { 
       push @temp_arr2, "$lvlfirst[$i]$lvlnext[$j]"; ##Trying to join here 

      } 
     } 
    } 

    return \@temp_arr2; 
} 

XML是:

<root> 
    <class1 name="A1"> 
    <class2 name="B1"> 
     <class3 name="C1"> 
     <class4 name="D1"></class4> 
     <class4 name="D2"></class4> 
     </class3> 
    </class2> 
    <class2 name="B2"> 
     <class3 name="C1"> 
     <class4 name="D1"></class4> 
     </class3> 
    </class2> 
    <class2 name="B3"> 
     <class3 name="C1"> 
     <class4 name="D1"></class4> 
     <class4 name="D2"></class4> 
     <class4 name="D3"></class4> 
     </class3> 
    </class2> 
    </class1> 
</root> 
+1

這聽起來像一個XY問題。你能詳細解釋一下嗎?通常遞歸結構是遞歸的原因。 – Sobrique

+0

@Sobrique輸入hashref是從xml中的數據分類層次結構生成的。我必須加入數據才能生成表示父子鏈接的字符串。 – waghso

+1

好的。我可以建議後退一步嗎?使用XML解析器 - 發佈您的XML,並且給定XML解析器隱式處理遞歸,我們可以更輕鬆地給出您想要的內容。 – Sobrique

回答

3

在來尋求幫助之前,你應該自己做點努力。我們更有可能幫助您修復破損的代碼,而不僅僅是給您一個答案。

但我感到慷慨,我有幾分鐘的時間。

蠻力方法是遍歷散列中每個級別的每個鍵。

#!/usr/bin/perl 

use strict; 
use warnings; 
use 5.010; 

use Data::Dumper; 

my $hash_ref = { 
    'A1' => { 
     'B2' => { 
      'C1' => { 
       'D1' => {}, 
       'D2' => {}, 
       'D3' => {} 
      } 
     }, 
     'B3' => { 
      'C1' => { 
       'D2' => {}, 
       'D1' => {}, 
       'D3' => {} 
      } 
     }, 
     'B1' => { 
      'C1' => { 
       'D1' => {}, 
       'D2' => {} 
      } 
     } 
    } 
}; 

my @arr; 

for my $l1 (sort keys %$hash_ref) { 
    for my $l2 (sort keys %{$hash_ref->{$l1}}) { 
    for my $l3 (sort keys %{$hash_ref->{$l1}{$l2}}) { 
     for my $l4 (sort keys %{$hash_ref->{$l1}{$l2}{$l3}}) { 
     push @arr, "$l1$l2$l3$l4"; 
     } 
    } 
    } 
} 

say Dumper \@arr; 

這將產生輸出:

$VAR1 = [ 
      'A1B1C1D1', 
      'A1B1C1D2', 
      'A1B2C1D1', 
      'A1B2C1D2', 
      'A1B2C1D3', 
      'A1B3C1D1', 
      'A1B3C1D2', 
      'A1B3C1D3' 
     ]; 

更新:這裏有一個遞歸解決方案:

#!/usr/bin/perl 

use strict; 
use warnings; 
use 5.010; 

use Data::Dumper; 

my $hash_ref = { 
    'A1' => { 
     'B2' => { 
      'C1' => { 
       'D1' => {}, 
       'D2' => {}, 
       'D3' => {} 
      } 
     }, 
     'B3' => { 
      'C1' => { 
       'D2' => {}, 
       'D1' => {}, 
       'D3' => {} 
      } 
     }, 
     'B1' => { 
      'C1' => { 
       'D1' => {}, 
       'D2' => {} 
      } 
     } 
    } 
}; 

my @arr = walk_hash($hash_ref, ''); 

say Dumper \@arr; 

sub walk_hash { 
    my ($hash_ref, $prefix) = @_; 

    return $prefix unless keys %$hash_ref; 
    return map { walk_hash($hash_ref->{$_}, "$prefix$_") } sort keys %$hash_ref; 
} 
+0

加了我想要的代碼 – waghso

+0

感謝您的回答戴夫。但是如果只有兩層嵌套,這段代碼將會失敗。我嘗試的哈希是動態嵌套,當我嘗試進一步編碼時,它變得太複雜了。 – waghso

+0

是的,擁有動態數量的散列級別意味着您需要一個遞歸解決方案。我可能有時間稍後再看一下。 –

2

我將採取不同的解決這個 - 因爲這是XML,我會跳過中間'將XML轉換爲散列'步驟,並直接使用它。

像這樣的東西你想要做什麼:

#!/usr/bin/env perl 
use strict; 
use warnings 'all'; 

use XML::Twig; 
use Data::Dumper; 

my $twig = XML::Twig -> new -> parsefile ('your.xml'); 

my @node_keys; 

#find all the nodes with a name attribute. 
#then grep out the ones that have child nodes. 
foreach my $elt (grep { not $_ -> descendants } $twig -> get_xpath('//*[@name]')){ 
    my $path = $elt -> att('name'); 
    my $cursor = $elt; 
    #recurse upwards through 'parent' nodes with a 'name' attribute. 
    while ($cursor -> parent -> att('name')) { 
     $path = $cursor -> parent -> att('name') . $path; 
     $cursor = $cursor -> parent; 
    } 
    push @node_keys, $path; 
} 

print Dumper \@node_keys; 

給出輸出:

$VAR1 = [ 
      'A1B1C1D1', 
      'A1B1C1D2', 
      'A1B2C1D1', 
      'A1B3C1D1', 
      'A1B3C1D2', 
      'A1B3C1D3' 
     ]; 

注意 - 因爲它是走在「XML秩序」它保留了相同的順序來源。這可能被稱爲功能,或者您可以在之後進行排序。

但是我會問,或許你正在試圖通過使這些'名稱'屬性的化合物來實現 - 你可以通過XML解析和xpath查詢更有效地解決任務。