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

I need a way to step through a hash, with unknown keys in it. The Hash of the Hash will be given by a string, $key in the example code below.

This code compiles without warnings or errors, but does not produce any output. How would one fix this problem?
#!/usr/bin/perl -w use strict; my %hash1 = (); $hash1{key1}{key2}{key3}{A} = "hello"; $hash1{key1}{key2}{key3}{B} = "bye"; my $key = "{key1}{key2}{key3}"; my $new_hash = {}; $new_hash = \%hash1; foreach (keys %{$$new_hash{$key}}) { print "$_ \n"; }

Replies are listed 'Best First'.
Re: eval on hash (use \\)
by tye (Sage) on Apr 09, 2003 at 17:28 UTC

    Based on (tye)Re: varying length multi-dimensional hashes:

    sub derefHashTree { my( $hv, @keys )= @_; my $ref= \$hv; for my $key ( @keys ) { $ref= \$$ref->{$key}; } return $$ref; } my %hash1; $hash1{key1}{key2}{key3}{A} = "hello"; $hash1{key1}{key2}{key3}{B} = "bye"; my $new_hash = \%hash1; my @keys= qw( key1 key2 key3 ); foreach( keys %{ derefHashTree($new_hash,@keys) } ) { print "$_\n"; }
    Note that you can return $ref; instead of $$ref if you want to modify the indicated value instead of just fetching it.

                    - tye
      To get a better understanding of what I could do with this piece of code, I tried to modify it as follows only to get this error: "delete argument is not a HASH or ARRAY element or slice at ./test2.pl line 29"
      #!/usr/bin/perl -w use strict; use Data::Dumper; sub derefHashTree { my( $hv, @keys )= @_; my $ref= \$hv; for my $key ( @keys ) { $ref= \$$ref->{$key}; } return $ref; } my %hash1; $hash1{key1}{key2}{key3}{A} = "hello"; $hash1{key1}{key2}{key3}{B} = "bye"; my $new_hash = \%hash1; my @keys= qw( key1 key2 key3 A); #foreach( keys %{ derefHashTree($new_hash,@keys) } ) { # print "$_\n"; #} my $new_ref = derefHashTree($new_hash,@keys); delete $new_ref; print Dumper(\%hash1);

      I've also tried "delete $$new_ref", "delete ${$new_ref}", "delete %{$new_ref}"

      Thanks

        You need to delay the last deref:

        my @keys= qw( key1 key2 key3 A ); my $last= pop(@keys); delete derefHashTree($new_hash,@keys)->{$last};

                        - tye
        Read delete for more info. You might be trying to use undef instead.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: eval on hash
by nothingmuch (Priest) on Apr 09, 2003 at 17:28 UTC
    I think you've grasped the problem by mentioning eval. $new_hash{ '{key1}{key2}{key3}' } is the actual key you're accessing, which is a Bad Thing™.

    You could use eval, but that would be wasteful:
    $\ = "\n"; foreach (eval "keys \%{ \$new_hash->$key }" ){ print }
    I think it's worth mentioning that %$new_hash and %hash1 are two names for the same thing.

    That set aside, here's a solution matching you're concept:
    my @path = qw(key1 key2 key3); my $reference = $new_hash; $reference = $reference->{$_} foreach @path; $\ = "\n"; foreach (keys %$reference){ print; }
    Update: I suggest rereading perlreftut and perlref to farmiliarise yourself with the concept of pointing at a structure. Perhaps you'll find a more suitable solution.

    -nuffin
    zz zZ Z Z #!perl
Re: eval on hash
by tall_man (Parson) on Apr 09, 2003 at 17:31 UTC
    Your $key doesn't work to address the hash, but this would work:
    foreach (keys %{$new_hash->{key1}->{key2}->{key3}}) { print "$_ \n"; }