Perl:动态深度

时间:2016-04-20 18:27:21

标签: perl hash hash-of-hashes

我正在努力访问/修改未知(即动态)深度的哈希值。

假设我正在读取文件中的度量表(长度,宽度,高度),然后计算面积和体积以创建如下的散列:

#                       #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。

感谢。

2 个答案:

答案 0 :(得分:5)

所以这是一个递归函数,或多或少地做你想要的东西:

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不会优化尾递归。

答案 1 :(得分:1)

看看“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;