如何在哈希散列中获取与哈希引用键相关联的键?

时间:2014-01-11 21:15:25

标签: perl hash perl-data-structures hash-of-hashes hashref

为了帮助我学习Perl,我构建了以下数据结构,其中内部哈希(/ DriveA / archive等)是哈希引用:

#The contents of the %properties hash of hashes
#The inner hash is a hash reference to a hash named %attributes

$VAR1 = {
    '/DriveA' => {
        '/DriveA/archive/' => {
            'MaxSize' => '20GB',
            'Size' => '19GB',
            'Free' => '5'
        },
        '/DriveA/current/' => {
            'MaxSize' => '20GB',
            'Size' => '12GB',
            'Free' => '40'
        }
    },
    '/DriveB' => {
        '/DriveB/archive/' => {
            'MaxSize' => '8GB',
            'Size' => '6GB',
            'Free' => '25'
        },
        '/DriveB/current/' => {
            'MaxSize' => '80GB',
            'Size' => '20GB',
            'Free' => '75'
        }
    },
    '/DriveC' => {
        '/DriveC/' => {
            'MaxSize' => '20GB',
            'Size' => '10GB',
            'Free' => '50'
        }
    }
}

我使用以下方法创建了一个数组来保存%attributes的键(也就是%属性中的值/哈希引用):

@list = sort keys %attributes;

我正在尝试迭代@list中的元素,并在%properties中找到外部哈希的关联键。因此,例如,如果/DriveA/archive/是数组中的下一个项目,我想从/DriveA中找到与该值%properties相关联的哈希键,假设取消引用内部哈希

我创建了一个反向哈希,它输出以下内容......

$VAR1 = {
    'HASH(0x2002f244)' => '/DriveB',
    'HASH(0x2002f388)' => '/DriveC',
    'HASH(0x2002f1e4)' => '/DriveA'
}

...使用此代码...

foreach my $item (@list) {
    my %rhash = reverse %properties;     # Reverse the hash of hashes so value is key
    print Dumper(\%rhash);
}

问题1:

鉴于上述情况,我将如何取消引用哈希,以便在哈希引用中找到$item,以便我可以确定关联值(而不是哈希引用值)。

如果$item = '/DriveA/archive/',我想在'/DriveA'的变量中捕获%properties,以便可以从子例程返回。

我知道内部哈希需要被解除引用,我只是不确定如何去做。我通读了perlrefperldscperllol,但我找不到答案。

感谢。

1 个答案:

答案 0 :(得分:1)

最简单的方法是直接通过遍历数据结构生成反向键:

my %reverse_keys;
foreach my $outer_key (keys %properties) {
    my $inner_hashref = $properties->{$outer_key};
    my %reverse_map = map { ($_ => $outer_key) } keys %$inner_hashref;
    %reverse_keys = (%reverse_keys, %reverse_map);
}

理想情况下,您甚至可以在将数据存储到%属性的同时直接生成%reverse_keys,因此您不需要上面的额外遍历代码。


解决您的实际技术问题:

  • 您开始使用哈希引用(基本上是C语言中的指针)。

  • 然后将该哈希引用作为键分配给哈希。

    • 将某些内容指定为散列键会将其置于字符串上下文(标量上下文的特例)。

    • 当您在Perl中对字符串进行字符串化时,它会变成该引用的字符串表示形式 - 这是您在Data :: Dumper反向散列时看到的HASH(0x2002f244)字符串。

  • 在技术层面上,您要问的是“如何将哈希引用的字符串表示形式转换回哈希引用本身?”

  • Perl FAQ 4中介绍了这一点。据我所知,你不能轻易地将哈希引用的字符串表示形式转换回哈希引用本身。

  • 如果您绝对必须(我强烈建议您反对 - 请使用答案顶部的解决方案) - 您可以使用Devel::Pointer CPAN模块执行此操作。

    使用该模块的解决方案显示在this PerlMonks thread


另一种解决方案可能是使用Tie::RefHash模块来使用实际的哈希引用而不是它们的字符串表示作为键。这将在第8.5.1章中介绍。 O'Reilly的“Programming Perl,3rd edition”中的“引用不作为哈希键”。我也建议不要那么疯狂。