Search code examples
perlhashwww-mechanizehash-of-hasheshashref

Perl accessing the elements in a hash/hash reference data structure


I have a question I'm hoping you could help with as I am new to hashes and hash reference stuff?

I have the following data structure:

$VAR1 = {
    'http://www.superuser.com/' => {
        'difference' => {
            'http://www.superuser.com/questions' => '10735',
            'http://www.superuser.com/faq' => '13095'
        },
        'equal' => {
            'http://www.superuser.com/ ' => '20892'
        }
    },
    'http://www.stackoverflow.com/' => {
        'difference' => {
            'http://www.stackoverflow.com/faq' => '13015',
            'http://www.stackoverflow.com/questions' => '10506'
        },
        'equal' => {
            'http://www.stackoverflow.com/ ' => '33362'
        }
    }

If I want to access all the URLs in the key 'difference' so I can then perform some other actions on the URLs, what is the correct or preferred method of accessing those elements?

e.g I will end up with the following URLs that I can then do stuff to in a foreach loop with:

http://www.superuser.com/questions
http://www.superuser.com/faq
http://www.stackoverflow.com/faq
http://www.stackoverflow.com/questions

------EDIT------

Code to access the elements further down the data structure shown above:

my @urls;
foreach my $key1 ( keys( %{$VAR1} ) ) {
    print( "$key1\n" );
    foreach my $key2 ( keys( %{$VAR1->{$key1}} ) ) {
        print( "\t$key2\n" );
    foreach my $key3 ( keys( %{$VAR1->{$key1}{$key2}} ) ) {
        print( "\t\t$key3\n" );
    push @urls, keys %{$VAR1->{$key1}{$key2}{$key3}};
    }
  }
}
print "@urls\n";

Using the code above why do I get the following error?

Can't use string ("13238") as a HASH ref while "strict refs" in use at ....


Solution

  • It is not difficult, just take the second level of keys off every key in the variable:

    my @urls;
    for my $key (keys %$VAR1) {
        push @urls, keys %{$VAR1->{$key}{'difference'}};
    }
    

    If you're struggling with dereferencing, just keep in mind that all values in a hash or array can only be a scalar value. In a multilevel hash or array the levels are just single hashes/arrays stacked on top of each other.

    For example, you could do:

    for my $value (values %$VAR1) {
        push @urls, keys %{$value->{'difference'}};
    }
    

    Or

    for my $name (keys %$VAR1) {
        my $site = $VAR1->{$name};
        push @urls, keys %{$site->{'difference'}};
    }
    

    ..taking the route either directly over the value (a reference to a hash) or over a temporary variable, representing the value via the key. There is more to read in perldoc perldata.