Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Traversing through HoH

by snape (Pilgrim)
on Apr 04, 2012 at 20:52 UTC ( [id://963527]=perlquestion: print w/replies, xml ) Need Help??

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

If you have a hash of hashes and you want to iterate across all values, what's the best way to do it. I would like to know if I coule iterate through Hash of hashes without using foreach twice (or number of times hashes are present). For example, I would like to do:

foreach my ($key1, $key2) (keys %hoh) { ### CODE ### }

instead of

foreach my $key1 (keys %hoh) { foreach $key2 (keys %{$hoh{$key1}) { ### CODE ### } }

I hope there is some way to do it. Thanks

Replies are listed 'Best First'.
Re: Traversing through HoH
by aaron_baugher (Curate) on Apr 04, 2012 at 21:22 UTC

    The usual way would be to go through it recursively. Something like this:

    #!/usr/bin/env perl use Modern::Perl; sub recurse { my $hashref = shift; for my $k (keys %$hashref){ if( ref $hashref->{$k} eq 'HASH' ){ recurse($hashref->{$k}); } else { # do stuff with $key and $value say "$k -> $hashref->{$k}"; } } } my %hash = ( one => { a => 11, b => 22, c => 33 }, two => 222, three => { A => { aa => 1111 }, B => { bb => 2222 } }, ); recurse(\%hash);

    I would also suspect that There Is A Module For That.

    Aaron B.
    My Woefully Neglected Blog, where I occasionally mention Perl.

Re: Traversing through HoH
by tangent (Parson) on Apr 04, 2012 at 23:43 UTC
    You can also use while with each, I find it reads better though it is still nested loops:
    while ( my ($key1,$hash1) = each %{$hoh} ) { while ( my ($key2,$value) = each %{$hash1} ) { ### CODE ### } }
Re: Traversing through HoH
by BrowserUk (Patriarch) on Apr 04, 2012 at 21:21 UTC

    You could do something like this, but it is certainly no easier or clearer than two nested loops:

    for my $keys ( map{ my $k=$_; map[ $k, $_ ],keys %{ $h{ $k}} } keys % +h ) { print "@$keys : ", $h{ $keys->[0] }{ $keys->[1] }; };; a a7 : 7 a a9 : 9 a a8 : 8 a a3 : 3 a a10 : 10 a a2 : 2 a a4 : 4 a a5 : 5 a a6 : 6 a a1 : 1 b b6 : 6 b b7 : 7 b b4 : 4 b b8 : 8 b b9 : 9 b b3 : 3 b b10 : 10 b b1 : 1 b b2 : 2 b b5 : 5 ...

    If you need to process a variable depth structure, then you might look at Data::Rmap or Data::Diver, but you may find them unsatisfying difficult to use.

    Every time I've tried to use the former, I've ended up reverting to a recursive subroutine tailored to my particular use.


    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: Traversing through HoH
by Anonymous Monk on Apr 04, 2012 at 21:45 UTC

      I think I want to make my code less wordy.. for example, I would prefer:

      print map $_,"\t",$hash{$_},"\n", sort keys %hash

      the above code as compared to

      foreach my $key (sort keys %hash){ print $key,"\t",$hash{$key},"\n"; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://963527]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (7)
As of 2024-04-23 11:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found