thanos1983 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

Although that this seems with a very common question I can not find solution to my problem. I have a hash that contains multiple levels and I am trying to extract the data of the final level.

I want to use for loops to reach the final level and then store the data to one level hash.

I have been reading online the perldoc Access and Printing of a HASH OF HASHES. Even I found a similar question Traverse an unknown multi-dimensional hash but it is not exactly what I want.

On the sample of code that I have created I can see the path of the hash clearly by using Data::Dumper but I want to use foreach loops so I can reach the final stage of my complex hash and extract the data to a simple single level hash.

Update: The %singleLevelHash = (); that I have defined I wan to contain the last level of data.

Update 2: I tried to use everybodies solution to get the desired output, but still I can not figure it how to do it. I will update also the title of my question.

I am trying to extract the final part of hash as given in the sample code under.

Sample of desired output:

%singleLevelHash = ( 'thirdLevelSampleKeyOne' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyTwo' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyThree' => 'thirdLevelSampleValue', );

This is the reason that I wanted to use the foreach loop. Sample of my code provided under.

Sample of code:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %singleLevelHash = (); my %multiLevelHash = ( 'firstSampleKey' => 'SampleValue', 'secondSampleKey' => { 'secondLevelSampleKey' => { 'thirdLevelSampleKeyOne' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyTwo' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyThree' => 'thirdLevelSampleValue', } } ); print Dumper \%multiLevelHash; foreach my $firstSampleKey ( sort keys %multiLevelHash ) { print $firstSampleKey . "\n"; foreach my $secondLevelSampleKey ( sort keys $multiLevelHash{$firs +tSampleKey} ) { print $secondLevelSampleKey . "\n"; } } __DATA__ $VAR1 = { 'firstSampleKey' => 'SampleValue', 'secondSampleKey' => { 'secondLevelSampleKey' => { 'thirdLev +elSampleKeyOne' => 'thirdLevelSampleValue', 'thirdLev +elSampleKeyThree' => 'thirdLevelSampleValue', 'thirdLev +elSampleKeyTwo' => 'thirdLevelSampleValue' } } }; firstSampleKey Type of argument to keys on reference must be unblessed hashref or arr +ayref at hash.pl line 21.

Any suggestions are much appreciated.

Seeking for Perl wisdom...on the process of learning...not there...yet!

Replies are listed 'Best First'.
Re: How to print a multi-level Hashes of Hashes without the use of a module
by golux (Chaplain) on Jan 25, 2015 at 01:47 UTC
    Hi thanos1983,

    Do you know about the ref function? You can use it to tell what kind of data is referenced, affecting how you handle it.

    Here's a very quick-and-dirty subroutine show_this() that uses ref to recursively inspect the contents of your hash. As such, it's a primitive replacement for Data::Dumper:

    #!/usr/bin/perl -w # use strict; use warnings; use Data::Dumper; my %singleLevelHash = (); my %multiLevelHash = ( 'firstSampleKey' => 'SampleValue', 'secondSampleKey' => { 'secondLevelSampleKey' => { 'thirdLevelSampleKeyOne' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyTwo' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyThree' => 'thirdLevelSampleValue', } } ); # print Dumper \%multiLevelHash; show_this(\%multiLevelHash); # foreach my $firstSampleKey ( sort keys %multiLevelHash ) { # print $firstSampleKey . "\n"; # foreach my $secondLevelSampleKey ( sort keys $multiLevelHash{$fi +rstSampleKey} ) { # print $secondLevelSampleKey . "\n"; # } # } sub show_this { my ($x) = @_; if (ref $x eq "") { printf " Value: '%s'\n", $x; } elsif (ref $x eq 'SCALAR') { printf " SCALAR ref: '%s'\n", $$x; } elsif (ref $x eq 'HASH') { print " HASH ref '$x':\n"; foreach my $key (keys %$x) { my $val = $x->{$key}; print " $key: "; show_this($val); } } elsif (ref $x eq 'ARRAY') { print " ARRAY re '$x':\n"; foreach my $val (@$x) { show_this($val); } } }

    Hopefully that gives you an idea how to interpret a HASH ref, differently from a scalar value. Hint -- the solution is in the block:

    foreach my $key (keys %$x) { ... }
    say  substr+lc crypt(qw $i3 SI$),4,5

      Hello golux,

      Thank you for your time and effort reading and replying to my post. I will try to play around with your suggesting to find my solution.

      I was not aware of the ref function, thanks for pointing this out.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: How to print a multi-level Hashes of Hashes without the use of a module
by BrowserUk (Patriarch) on Jan 25, 2015 at 02:11 UTC

    #! perl -slw use strict; use Data::Dump qw[ pp ]; sub dumpIt { my $r = shift; my $d = shift() // 1; die "'$r' not a hashref" unless ref $r eq 'HASH'; print "{" if $d == 1; for( keys %$r ) { if( ref $r->{ $_ } ) { print chr(9) x $d, "$_ => {"; dumpIt( $r->{ $_ }, $d + 1 ); print chr(9) x $d, "}"; } else { print chr(9) x $d, "$_ => $r->{ $_ }"; } } print "}" if $d == 1; } my %multiLevelHash = ( 'firstSampleKey' => 'SampleValue', 'secondSampleKey' => { 'secondLevelSampleKey' => { 'thirdLevelSampleKeyOne' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyTwo' => 'thirdLevelSampleValue', 'thirdLevelSampleKeyThree' => { 'fourthLevelSampleKey' => 'fourthLevelSampleValue', } } } ); dumpIt( \%multiLevelHash ); __END__ C:\test>junk90 { firstSampleKey => SampleValue secondSampleKey => { secondLevelSampleKey => { thirdLevelSampleKeyTwo => thirdLevelSampleValu +e thirdLevelSampleKeyThree => { fourthLevelSampleKey => fourthLevelSam +pleValue } thirdLevelSampleKeyOne => thirdLevelSampleValu +e } } }

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

      Hello BrowserUk,

      Thank you for your time and effort. I will try to experiment with your solution a little bit to become familiar. I was not aware that you can call the same subroutine inside the actual subroutine.

      Again thank you for your time and effort reading my question and replying.

      Seeking for Perl wisdom...on the process of learning...not there...yet!
        I was not aware that you can call the same subroutine inside the actual subroutine.

        You may want to have a look at recursion, which Perl supports.

Re: How to print a multi-level Hashes of Hashes and extract parts of it
by Laurent_R (Canon) on Jan 25, 2015 at 22:54 UTC
    You have already been given good answers, but I thought I could share here some code that I wrote for an answer I made about five days ago to a similar question on another forum (http://perlguru.com/gforum.cgi?post=80741;guest=19041527. It provides a very sketchy and incomplete prototype implementation of a dumper function somewhat similar to the Data::Dumper module (but much less advanced). The data sample used in this example is not yours, but you could very easily replace the content of the $response variable below with your own data sample. The output is far from being as rich as Data::Dumper and offers a lot of opportunities for improvement, but let's say that we have a reasonably good proof of concept. My aim for this post on the other forum was anyway not to write a replacement for Data::Dumper, but only to demonstrate how to traverse a nested data structure in which the nodes might be hash or array references. And, BTW, my approach is also recursive. I do not think that I need to repeat how recursion is important, others have stated it quite clearly.

    Je suis Charlie.