2016-04-20 63 views
0

我很努力地访问/修改未知(即动态)深度的哈希。Perl:访问动态深度的哈希

假如我是读的测量表(长,宽,高)从一个文件,然后计算面积和体积,以创建像下面这样的散列:

#      #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层密钥。

如果有或多或少有什么,我只在运行时发现?例如。如果文件中只有长度和宽度,那么如何编写代码,然后访问像$results{2}{3}{'Area'}这样的散列?

I.e.给定一个散列和动态长度的嵌套关键字列表,这些关键字可能会或可能不会在该散列中产生一个条目,您如何访问散列以查找基本事物,如检查该键组合是否有值或修改值?

我几乎要的符号,如:

my @hashkeys = (2,3,7); 

if exists ($hash{join("->",@hashkeys)}){ 
    print "Found it!\n"; 
} 

我知道你可以访问散列子哈希值,并得到他们的引用,以便在最后的例子,我可以通过@hashkeys迭代,为每一个如果检查当前散列在该键上具有子散列,如果是,则保存对下一次迭代的该子散列的引用。然而,这感觉很复杂,我怀疑已经有一种方法可以更容易地做到这一点。

希望这足以理解我的问题,但如果不是,我可以尝试处理MWE。

谢谢。

+4

这似乎不是一个很好的数据结构。首先,你不能有两个具有相同维度的项目,因为散列键是唯一的。使用具有“长度”键,“宽度”和“高度”的扁平结构会更有意义。 – ThisSuitIsBlackNot

+0

嗨,我不确定这是一个限制。这仅仅是我为工作而做的更复杂的事情的一个简化例子,但即使在这里,当我遇到一组给定的度量时,我可以直接将它们索引到散列中以找出区域等。如果我看到相同的测量结果两次,我不需要重新计算面积等。这就是为什么我使用嵌套散列与每个级别的键是一个单独的测量。 – SSilk

+0

这是真实的数据吗?或者你是否提供占位符数据,还是作业?作为[@ThisSuitIsBlackNot上面说](http://stackoverflow.com/questions/36752179/perl-access-hash-of-dynamic-depth#comment61084783_36752179)我不明白为什么你在第一次组织这样的事情地点。正如你所见,这是有问题的。这听起来像你只是一个*长度,宽度,高度,面积和体积的东西*的列表,其中一些可能会丢失,我会像这样构造它:作为一个由五个项目组成的数组。如果取决于你的应用如何以更快的速度访问特定条目 – Borodin

回答

4

所以这里有一个递归函数,你想要什么做哪些或多或少:

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

+0

我认为这是真正的答案,因为它确实回答了我的问题,但对于那些考虑采用类似方法的其他人,请首先查看我的问题下面的评论。如上所述,我最终改变了我的方法,因此从一开始就没有深思熟虑。谢谢。 – SSilk

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; 
+0

'$;'的要点是,它会魔法地将'$ foo {@keys}'变成'$ foo {join $ ;, @keys}'。如果你打算这样做,你可能会更容易地使用分隔符,并且更像'''那样适合数据。 – Schwern