Perl:访问动态深度的散列
Perl: Access hash of dynamic depth
我正在努力访问/修改未知(即动态)深度的哈希值。
假设我正在从文件中读取 table 测量值(长度、宽度、高度),然后计算面积和体积以创建如下所示的散列:
# #Length Width Height Results
my %results = (
'2' => {
'3' => {
'7' => {
'Area' => 6,
'Volume' => 42,
},
},
},
'6' => {
'4' => {
'2' => {
'Area' => 24,
'Volume' => 48,
},
},
},
);
我了解如何访问散列中的单个项目,例如$results{2}{3}{7}{'Area'}
会给我 6
,或者我可以使用 exists $results{2}{3}{7}{'Area'}
检查输入文件中是否找到了该测量组合。然而,带有一系列 {}
大括号的符号假定我在编写代码时知道将有 4 层键。
如果有更多或更少,我只是在运行时才发现怎么办?例如。如果文件中只有 Length 和 Width,您将如何编写代码来访问像 $results{2}{3}{'Area'}
?
这样的哈希
即给定一个散列和嵌套键的动态长度列表,在该散列中可能有也可能没有结果条目,您如何访问散列以进行基本操作,例如检查该键组合是否有值或修改该值?
我几乎想要这样的符号:
my @hashkeys = (2,3,7);
if exists ( $hash{join("->",@hashkeys)} ){
print "Found it!\n";
}
我知道您可以访问散列的子散列并获取它们的引用,因此在最后一个示例中我可以遍历 @hashkeys
,检查当前散列是否有子散列键,如果是,则为下一次迭代保存对该子哈希的引用。然而,这感觉很复杂,我怀疑已经有一种方法可以更容易地做到这一点。
希望这足以理解我的问题,但如果没有,我可以尝试建立 MWE。
谢谢。
所以这是一个递归函数,它或多或少地完成了你想要的:
sub fetch {
my $ref = shift;
my $key = shift;
my @remaining_path = @_;
return undef unless ref $ref;
return undef unless defined $ref->{$key};
return $ref->{$key} unless scalar @remaining_path;
return fetch($ref->{$key}, @remaining_path);
}
fetch(\%results, 2, 3, 7, 'Volume'); # 42
fetch(\%results, 2, 3); # hashref
fetch(\%results, 2, 3, 7, 'Area', 8); # undef
fetch(\%results, 2, 3, 8, 'Area'); # undef
但是请检查其他人已经给出的关于错误数据结构的评论,因为它是非常真实的。如果你仍然认为这是你需要的,至少使用 for 循环重写它,因为 perl 没有优化尾递归。
在 "man perlvar" 中查看 $;
。
http://perldoc.perl.org/perlvar.html#%24%3b
你可以用变长数组转单键的思路
my %foo;
my (@KEYS)=(2,3,7);
$foo{ join( $; , @KEYS ) }{Area}=6;
$foo{ join( $; , @KEYS ) }{Volume}=42;
我正在努力访问/修改未知(即动态)深度的哈希值。
假设我正在从文件中读取 table 测量值(长度、宽度、高度),然后计算面积和体积以创建如下所示的散列:
# #Length Width Height Results
my %results = (
'2' => {
'3' => {
'7' => {
'Area' => 6,
'Volume' => 42,
},
},
},
'6' => {
'4' => {
'2' => {
'Area' => 24,
'Volume' => 48,
},
},
},
);
我了解如何访问散列中的单个项目,例如$results{2}{3}{7}{'Area'}
会给我 6
,或者我可以使用 exists $results{2}{3}{7}{'Area'}
检查输入文件中是否找到了该测量组合。然而,带有一系列 {}
大括号的符号假定我在编写代码时知道将有 4 层键。
如果有更多或更少,我只是在运行时才发现怎么办?例如。如果文件中只有 Length 和 Width,您将如何编写代码来访问像 $results{2}{3}{'Area'}
?
即给定一个散列和嵌套键的动态长度列表,在该散列中可能有也可能没有结果条目,您如何访问散列以进行基本操作,例如检查该键组合是否有值或修改该值?
我几乎想要这样的符号:
my @hashkeys = (2,3,7);
if exists ( $hash{join("->",@hashkeys)} ){
print "Found it!\n";
}
我知道您可以访问散列的子散列并获取它们的引用,因此在最后一个示例中我可以遍历 @hashkeys
,检查当前散列是否有子散列键,如果是,则为下一次迭代保存对该子哈希的引用。然而,这感觉很复杂,我怀疑已经有一种方法可以更容易地做到这一点。
希望这足以理解我的问题,但如果没有,我可以尝试建立 MWE。
谢谢。
所以这是一个递归函数,它或多或少地完成了你想要的:
sub fetch {
my $ref = shift;
my $key = shift;
my @remaining_path = @_;
return undef unless ref $ref;
return undef unless defined $ref->{$key};
return $ref->{$key} unless scalar @remaining_path;
return fetch($ref->{$key}, @remaining_path);
}
fetch(\%results, 2, 3, 7, 'Volume'); # 42
fetch(\%results, 2, 3); # hashref
fetch(\%results, 2, 3, 7, 'Area', 8); # undef
fetch(\%results, 2, 3, 8, 'Area'); # undef
但是请检查其他人已经给出的关于错误数据结构的评论,因为它是非常真实的。如果你仍然认为这是你需要的,至少使用 for 循环重写它,因为 perl 没有优化尾递归。
在 "man perlvar" 中查看 $;
。
http://perldoc.perl.org/perlvar.html#%24%3b
你可以用变长数组转单键的思路
my %foo;
my (@KEYS)=(2,3,7);
$foo{ join( $; , @KEYS ) }{Area}=6;
$foo{ join( $; , @KEYS ) }{Volume}=42;