从引用哈希生成数组

时间:2016-07-26 10:28:36

标签: arrays perl hash

我试图从散列引用生成数组,通过加入散列的所有哈希键来创建。 考虑我有动态哈希引用,如

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>

2 个答案:

答案 0 :(得分:3)

在来SO寻求帮助之前,你应该自己做一些努力。我们更有可能帮助您修复损坏的代码,而不仅仅是给您一个答案。

但是我感觉很慷慨,我还有几分钟的时间。

蛮力方法是遍历散列中每个级别的每个键。

#!/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;
}

答案 1 :(得分:2)

我会以不同的方式解决这个问题 - 因为这是XML,我会跳过中间版,将XML格式化为哈希格式&#39;一步,直接使用它。

这样的事情符合你的要求:

#!/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顺序行走&#39;它保留了与源相同的顺序。这可能被称为功能,或者您可以在之后对其进行排序。

但是我可能会质疑,通过制作这些名称&#39;的化合物,你想要实现的目标。属性 - 可能是您可以通过XML解析和xpath查询更有效地解决任务。