-1

I have a question I'm hoping you could help with?

This is the last part I need help with in understanding hash references

Code:

my $content_lengths; # this is at the top
foreach my $url ( # ... more stuff

# compare
if ( $mech->response->header('Content-Length') != $content_length ) {
  print "$child_url: different content length: $content_length vs "
    . $mech->response->header('Content-Length') . "!\n";

  # store the urls that are found to have different content
  # lengths to the base url only if the same url has not already been stored
  $content_lengths->{$url}->{'different'}->{$child_url} = $mech->response->header('Content-Length');

} elsif ( $mech->response->header('Content-Length') == $content_length ) {
  print "Content lengths are the same\n";

  # store the urls that are found to have the same content length as the base
  # url only if the same url has not already been stored
  $content_lengths->{$url}->{'equal'}->{$child_url} = $mech->response->header('Content-Length');
}

What it looked like using Data::Dumper

$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'
                                                      }
                                         }
    };

What I need help with:

I need help understanding the various ways of accessing the different parts in the hash reference and using them to do things, such as print them.

So for example how do I print all the $url from the hash reference (i.e from Data::Dumper that will be http://www.superuser.com/ and http://www.stackoverflow.com/)

and how do I print all the $child_url or a particular one/subset from $child_url and so on?

Your help with this is much appreciated,

thanks a lot

yonetpkbji
  • 1,019
  • 2
  • 21
  • 35

1 Answers1

1

You can navigate your hashref thusly:

$hashref->{key1}{key2}{keyN};

For example, if you want the superuser equal branch:

my $urlArrayref = $hashref->{'http://www.superuser.com/'}{'equal'};

More to the point, to print the urls (first level key) of the hashref, you would do:

foreach my $key ( keys( %{$hashref} ) ) {
    print( "key is '$key'\n" );
}

Then if you wanted the second level keys:

foreach my $firstLevelKey ( keys( %{$hashref} ) ) {
    print( "first level key is '$firstLevelKey'\n" );
    foreach my $secondLevelKey ( keys( %{$hashref->{$firstLevelKey}} ) ) {
        print( "\tfirst level key is '$secondLevelKey'\n" );
    }
}

And so forth...

----- EDIT -----

This is working sample code from your example above:

#!/usr/bin/perl

use strict;
use warnings;

my $content_lengths = {
    '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'
        }
    }
};

foreach my $key1 ( keys( %{$content_lengths} ) ) {
    print( "$key1\n" );
    foreach my $key2 ( keys( %{$content_lengths->{$key1}} ) ) {
        print( "\t$key2\n" );
        foreach my $key3 ( keys( %{$content_lengths->{$key1}{$key2}} ) ) {
            print( "\t\t$key3\n" );
        }
    }
}

Which results in this output:

http://www.superuser.com/
        difference
                http://www.superuser.com/questions
                http://www.superuser.com/faq
        equal
                http://www.superuser.com/
http://www.stackoverflow.com/
        difference
                http://www.stackoverflow.com/faq
                http://www.stackoverflow.com/questions
        equal
                http://www.stackoverflow.com/
Lucas
  • 14,227
  • 9
  • 74
  • 124
  • Hi, would you be able to show me what the code would look like for my examples please, as when I to do a `foreach` using your example as a template I get errors such as 'Type of arg 1 to keys must be hash (not array dereference)'? thanks for your help – yonetpkbji Feb 14 '13 at 10:56
  • I cant get some data if i use `foreach my $here (keys %{$content_lengths} ) { print( "key is '$here'\n"); }` ? but not when I use `foreach my $key ( keys( @{$content_lengths} ) ) { print( "key is '$key'\n" );` } ? – yonetpkbji Feb 14 '13 at 11:06
  • 1
    @perl-user, sorry it was a typo... should have been `keys( %{$content_lengths} )` as you figured out. i updated my answer above. – Lucas Feb 14 '13 at 15:43
  • @perl-user, does that answer your question? – Lucas Feb 14 '13 at 15:56
  • One last thing, is it possible to do something like 'only get the 2nd element in the `http://www.stackoverflow.com/' => { 'difference' => {` hash' (which would be 'http: //www.stackoverflow.com/questions' => '10506' using the data structure shown in my question) without actually knowing what the element was? like you would with an array using `@array[1]` and so on? thanks for your help – yonetpkbji Feb 14 '13 at 16:08
  • @perl-user: Hashes are in no particular order. There is no second element. You could of course sort the keys and get the value to the second one in the list of sorted keys. See http://www.perlmonks.org/?node_id=845520 for example. – simbabque Feb 14 '13 at 16:52
  • @Lucas - thanks that explains it well. Also, referring to the code and data structure in my question, why does this piece of code not work? `foreach my $here (keys( %{$content_lengths->{$url}}) ) { print( "key is $here\n"); }` , I thought it should print the second level keys like in your example code? I can print the first level keys okay using `foreach my $here (keys %{$content_lengths} ) { print( "key is $here\n"); }`? – yonetpkbji Feb 14 '13 at 17:00
  • 1
    @perl-user, you must have a typo or something. I tested this code, see the edit above. It works. – Lucas Feb 14 '13 at 17:22
  • @Lucas - Yes your right, it was something I was doing wrong, your new code showed what I was doing wrong, thanks. Is it the case that you can only access the data further down the data structure in this `foreach` nested fashion you've showed me? or is there another way to access it directly? thanks a lot – yonetpkbji Feb 15 '13 at 09:25
  • @perl-user, you can access any element directly with `$content_lengths->{key1}{key2}{keyN}`... Not sure what else you might mean by that. – Lucas Feb 15 '13 at 15:55
  • @Lucas - Yes that's what I was looking for, thanks for all your help, appreciate it. – yonetpkbji Feb 18 '13 at 12:08