假设嵌套的哈希结构%old_hash..
my %old_hash;
$old_hash{"foo"}{"bar"}{"zonk"} = "hello";
Run Code Online (Sandbox Code Playgroud)
..我们想要"扁平化"(对不起,如果这是错误的术语!)使用sub的非嵌套哈希,&flatten(...)以便...
my %h = &flatten(\%old_hash);
die unless($h{"zonk"} eq "hello");
Run Code Online (Sandbox Code Playgroud)
以下定义&flatten(...)的诀窍是:
sub flatten {
my $hashref = shift;
my %hash;
my %i = %{$hashref};
foreach my $ii (keys(%i)) {
my %j = %{$i{$ii}};
foreach my $jj (keys(%j)) {
my %k = %{$j{$jj}};
foreach my $kk (keys(%k)) {
my $value = $k{$kk};
$hash{$kk} = $value;
}
}
}
return %hash;
}
Run Code Online (Sandbox Code Playgroud)
虽然给出的代码有效但它不是非常易读或干净.
我的问题是双重的:
rjh*_*rjh 10
您的方法不是最佳实践,因为它不能扩展.如果嵌套哈希是六个,十个级别深度怎么办?重复应该告诉你,递归例程可能就是你需要的.
sub flatten {
my ($in, $out) = @_;
for my $key (keys %$in) {
my $value = $in->{$key};
if ( defined $value && ref $value eq 'HASH' ) {
flatten($value, $out);
}
else {
$out->{$key} = $value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
或者,良好的现代Perl风格是尽可能使用CPAN.Data :: Traverse可以满足您的需求:
use Data::Traverse;
sub flatten {
my %hash = @_;
my %flattened;
traverse { $flattened{$a} = $b } \%hash;
return %flattened;
}
Run Code Online (Sandbox Code Playgroud)
最后要注意的是,通过引用传递哈希值通常更有效,以避免它们扩展到列表中然后再次变为哈希值.