Perl 如何创建哈希的递归哈希?(无限深)
请,我尝试创建一个复杂的数据结构。我知道怎么做Perl 如何创建哈希的递归哈希?(无限深),perl,data-structures,Perl,Data Structures,请,我尝试创建一个复杂的数据结构。我知道怎么做 $branch{'level1'}{'level2'}{'level3'}='leaf'; 但我不知道如何创造 $branch{'level1'}....{'levelN'}='leaf'; 我试着这样做: $branch{'leaf'} = "1"; $branchREF = \%branch; $branchtmp{'level3'} = $branchREF; 因此,我成功地得到: $VAR1 = 'level3'; $VAR2 = {
$branch{'level1'}{'level2'}{'level3'}='leaf';
但我不知道如何创造
$branch{'level1'}....{'levelN'}='leaf';
我试着这样做:
$branch{'leaf'} = "1";
$branchREF = \%branch;
$branchtmp{'level3'} = $branchREF;
因此,我成功地得到:
$VAR1 = 'level3';
$VAR2 = {
'leaf' => '1'
};
但对于下一步,要对哈希进行重新创建的N哈希,我尝试:
%branch = %branchtmp;
但结果是完全错误的<代码>%branch不是我所期望的。为了实现递归性,我需要重用我的第一个%分支
,而不是创建一个新分支。请问我该怎么办
A.可以帮助您:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Diver qw{ DiveVal };
use Data::Dumper;
my %branch;
DiveVal(\%branch, map "level$_", 1 .. 3) = 'leave';
print Dumper \%branch;
输出:
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leave'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
或者,如果您想自己实施:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
sub set_value {
my ($struct, @list) = @_;
if (@list > 2) {
set_value($struct->{ $list[0] } = {}, @list[ 1 .. $#list ]);
} else {
$struct->{ $list[0] } = $list[1];
}
}
my %branch;
set_value(\%branch, map("level$_", 1 .. 3), 'leave');
print Dumper \%branch;
最简单的方法是记住perl如何处理多维数据结构。它是通过引用来实现的。因此,您可能会发现从顶层开始更简单,而是作为散列引用:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
my @levels = qw ( level1 level2 level3 );
my $branch = {};
my $tail = pop(@levels);
my $cursor = $branch;
#iterate our levels
foreach my $level (@levels) {
#make a new anon-hash if there isn't one.
$cursor -> {$level} ||= {};
#traverse down
$cursor = $cursor->{$level};
}
#set a value
$cursor -> {$tail} = 'leaf';
print Dumper $branch;
输出:
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leave'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
注意-为了再次执行此操作,您必须重置光标并“重新遍历”,但可以以类似的方式“遍历”结构 一个简单的递归解决方案:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
sub recursiveHash {
my ($result, @rest) = @_;
return $result unless @rest;
my $nextTag = pop @rest;
return recursiveHash( {$nextTag => $result}, @rest);
}
print Dumper(recursiveHash('leaf', 'level1', 'level2', 'level3'));
输出:
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leave'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
$VAR1 = {
'level1' => {
'level2' => {
'level3' => 'leaf'
}
}
};
也就是说,Perl中的子例程调用相当慢。幸运的是,这里完全不需要递归
sub iterativeHash {
my ($result, @rest) = @_;
while (@rest) {
my $nextTag = pop @rest;
$result = { $nextTag => $result };
}
return $result;
}
我强烈建议使用现有的解决方案,例如
显然,它也可以在没有模块的情况下完成
sub DiveVal :lvalue {
my $p = \shift;
$p = \( $$p->{$_} ) for @_;
$$p
}
my @keys = map "level$_", 1 .. 3;
my $branch;
DiveVal($branch, @keys) = 'leaf';
-or-
my %branch;
DiveVal(\%branch, @keys) = 'leaf';
my
DiveVal
的工作原理:
Pre-loop:$p引用$branch
循环传递0之后:$p引用$branch->{level1}
在循环过程1之后:$p引用$branch->{level1}{level2}
循环传递2之后:$p引用$branch->{level1}{level2}{level3}
返回:$branch->{level1}{level2}{level3}
额外的间接层次有很多好处
- 它消除了对最后一个键进行特殊处理的需要
- 它消除了在取消引用散列之前创建散列的需要
- 它消除了根作为散列引用的需要。相反,任何标量都可以是根,甚至是未定义的根
- 它使扩展
以支持混合数组/散列结构变得容易DiveVal
- 李>
我对每个人的回答速度印象深刻!我真的很喜欢你回答这个问题的方式:我不需要额外的模块,而且我发现递归的方式非常简单。所以我得到了你的答案,但是Sobrique和Choroba的答案也很好。谢谢!:)不幸的是,这种方法不能用于添加到现有结构中,如
DiveVal($root,@keys)=$leaf代码>可以。谢谢你,乔洛巴。我倾向于第二种方法,不需要额外的模块,但我觉得eballes方法更简单一点。谢谢你的回答!:)@choroba,你可能有兴趣看看。如果你同时替换$cursor=代码>与$cursor=\(…)
并调整$cursor
的所有其他实例。谢谢你的回答,我从中学到了很多。我只想链接到。我需要它:)@ikegami,如果你是Data::Diver的作者,我已经通过CPAN向你发送了一封电子邮件,即发送到你的CPAN.org电子邮件地址。我不确定该电子邮件是否会转发到您的真实电子邮件地址。@Bulrush,我不维护该模块。我的CPAN名称与我的SO名称相同。是的,CPAN地址是邮件转发器。