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

I have a module that I am using that returns a multi-dimensional hash

My script gets data returned as
use strict; use warnings my $returnedData = $findVars->get();


I can access the data individually like
$returnedData->{..}{..};


Of Course replace the .. with a string, number, or variable of choice What I am wondering is how do I go about doing a foreach(keys ...) on something that complex

If I try to do a foreach(keys $returnedData) I of course get an error telling me that I cant do this because $returnedData is a scalar, not a hash. Any wisdom?

Replies are listed 'Best First'.
Re: Multi Dimensional Hashes
by mifflin (Curate) on Jun 07, 2005 at 03:03 UTC
    This should loop through your data structure...
    for my $key1 (keys %$returnedData) { for my $key2 (keys %{$returnedData->{$key1}}) { print "$key1.$key2 = $returnedData->{$key1}->{$key2}\n"; } }
    ps. not tested

    updated: here is a sample
    C:\tmp>type erick.pl my $returnedData = { key1 => { key5 => 'data1', key6 => 'data2', key7 => 'data3', key8 => 'data4', }, key2 => { key9 => 'data5', key10 => 'data6', key11 => 'data7', key12 => 'data8', }, key3 => { key13 => 'data9', key14 => 'data10', key15 => 'data11', key16 => 'data12', }, key4 => { key17 => 'data13', key18 => 'data14', key19 => 'data15', key20 => 'data16', }, }; for my $key1 (keys %$returnedData) { for my $key2 (keys %{$returnedData->{$key1}}) { print "$key1.$key2 = $returnedData->{$key1}->{$key2}\n"; } } C:\tmp>erick.pl key2.key10 = data6 key2.key12 = data8 key2.key9 = data5 key2.key11 = data7 key4.key19 = data15 key4.key18 = data14 key4.key17 = data13 key4.key20 = data16 key1.key5 = data1 key1.key6 = data2 key1.key8 = data4 key1.key7 = data3 key3.key15 = data11 key3.key13 = data9 key3.key14 = data10 key3.key16 = data12
Re: Multi Dimensional Hashes
by ysth (Canon) on Jun 07, 2005 at 02:58 UTC
    foreach (keys %$returnedData)
Re: Multi Dimensional Hashes
by kaif (Friar) on Jun 07, 2005 at 03:44 UTC

    If you would like to read on how to work with such structures in more detail, see The Perl Data Structures Cookbook. It contains valuable information on how to work with hashes of hashes, as well as all /(array|hashe)s of (array|hashe)s/ combinations and more.

    Although the above reference is great and more than enough, you may also wish to see the Categorized Q&A on nested data structures.

Re: Multi Dimensional Hashes
by joelnackman (Beadle) on Jun 07, 2005 at 03:08 UTC
    If $returnedData is holding a reference to a hash, you can get the keys of the outer hash by using keys %$returnedData. I'm not sure about the inner hashes, but I think that you could use keys %$returnedData->{..}.

    update: sorry, other replies came in while I was typing, that keeps happening to me.
      I think that you could use keys %$returnedData->{..}
      Not quite. The rule is that it's sigil followed by block returning reference of the appropriate type, but the braces can be left off iff the reference is a simple scalar variable. So you can do keys %$returnedData, but you'd need the braces for keys %{$returnedData->{...}}. Otherwise, it would parse as (keys %$returnedData)->{...}, which is nonsense.

      Caution: Contents may have been coded under pressure.
        So would I be correct if I said that the %{} around $returnedData->{..} is getting the hash inside of $returnedData->{..}?
Re: Multi Dimensional Hashes
by chas (Priest) on Jun 07, 2005 at 03:19 UTC
    It depends a lbit on exactly what you want to extract, but $returnedData is a reference to a hash; that hash is %{$returnedData}. Its values are references to hashes. You can use the keys function on %{$returnedData}, for example. You can print "everything" by something like:
    %HoH=%{$returnedData}; foreach $x(keys %HoH){ print "$x: "; foreach $y (keys %{$HoH{$x}}){ print "$y=$HoH{$x}{$y} "; } print "\n"; }

    You can use $returnedData directly without %HoH, but it is a bit more complicated to read.
    chas
    (Update: A lot of replies appeared while I was writing my reply...)
Re: Multi Dimensional Hashes
by TedPride (Priest) on Jun 07, 2005 at 07:07 UTC
    use strict; use warnings; my $p1 = {'a' => {'x' => 10, 'y' => 20}}; for (sort keys %$p1) { print "$_\n"; my $p2 = $p1->{$_}; for (sort keys %$p2) { print " $_ => $p2->{$_}\n"; } }
Re: Multi Dimensional Hashes
by tphyahoo (Vicar) on Jun 07, 2005 at 08:37 UTC
    I think an important issue you are dealing with here, in terms of terminology for thinking about the problem, is "deep copy" versus "shallow copy". See Copy of an anonymous hash for a discussion of this.

    I am still not real knowledgeable in this area, but I believe that is your problem space. Hope this helps.