我正在尝试从哈希引用生成数组,该引用是通过将哈希的所有键与排序连接来创建的。考虑我有像这样的动态哈希引用
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>
在向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;
}
我会以不同的方式处理这个问题——因为这是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顺序"行走的,所以它保留了与源代码相同的顺序。这可能被称为一个特性,或者您可以稍后对其进行排序。
但我可能会质疑,通过制作这些"name"属性的组合,您试图实现什么——您可能可以通过XML解析和xpath
查询更有效地解决任务。