How to get the key associated with a hash reference's key in a hash of hashes?

≯℡__Kan透↙ 提交于 2019-12-11 01:11:49

问题


In an attempt to help me learn Perl, I built the following data structure, where the inner hash (/DriveA/archive, etc.) is a hash reference:

#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'
        }
    }
}

I created an array to hold the keys for %attributes (aka the values/hash reference in %properties) using:

@list = sort keys %attributes;

I'm trying to iterate over the elements in @list and find the associated key for the outer hash in %properties. So, for example, if /DriveA/archive/ is the next item in the array, I want to find the hash key associated with that value, /DriveA, from %properties, assuming dereference of the inner hash.

I created a reverse hash, which outputs the following...

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

...using this code...

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

Question 1:

Given the above, how would I dereference the hash so I can find $item in the hash reference so I can determine the associated value (not the hash reference value).

If $item = '/DriveA/archive/', I want to capture '/DriveA' in a variable from %properties so it can be returned from a subroutine.

I know the inner hash needs to be dereferenced, I'm just not sure how to do it. I've read through perlref, perldsc, and perllol, but I haven't been able to find the answer.

Thanks.


回答1:


The easiest thing to do is to just generate the reverse keys directly by traversing the data structure:

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);
}

Ideally, you can even generate %reverse_keys directly at the same time you're stashing data into %properties, so you don't need that extra traversal code above.


To address your actual technical question:

  • You are starting with a hash reference (basically, a pointer in C vernacular).

  • Then you assign that hash reference as a key into a hash.

    • Assigning something as a hash key puts it into a string context (a special case of scalar context).

    • When you stringify a hash reference in Perl, it gets turned into a string representation of that reference - that's your HASH(0x2002f244) string you see when you Data::Dumper your reverse hash.

  • What you're asking is, on a technical level, is "how do I convert the string representation of a hash reference back into the hash reference itself?"

  • This is covered in Perl FAQ 4. As far as I'm aware, you can NOT easily convert the string representation of a hash reference back into the hash reference itself.

  • If you absolutely must (which I strongly recommend against - instead, use the solution at the top of the answer) - you can do so using Devel::Pointer CPAN module.

    A solution using that module is shown in this PerlMonks thread.


An additional solution may be to use Tie::RefHash module to use actual hash references instead of their string representations as keys. This is documented in Chapter 8.5.1. "References Don't Work as Hash Keys" of O'Reilly's "Programming Perl, 3rd edition". I would recommend against that bit of madness as well.



来源:https://stackoverflow.com/questions/21067972/how-to-get-the-key-associated-with-a-hash-references-key-in-a-hash-of-hashes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!