2016-07-26 65 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查询更有效地解决任务。