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

Hi,

This is probably easy, but I have a mental block. I have a big unwieldy hash that I want to operate on at a certain key nest depth. I want to loop through some update records, access the appropriate sub-hash, use a very short local variable to reference said sub-hash, munge the data, and have the original hash update as I update the short local variable (a reference, I'd think). The following code doesn't work, but I think conveys the essence of what I want (that is, I want %a to have $a{'WI'}{'GreenBay'}{'Color'} equal to 'White'):
use Data::Dumper; my %a; $a{'WI'}{'GreenBay'}{'Color'} = 'Black'; foreach my $update ("WI,GreenBay,White") { my ($state,$city,$color) = split /,/, $updtate; my $h = \$a{$state}{$city}; $h->{'Color'} = $color; }; print Dumper(\%a), "\n";
Is there a similar way of doing this that allows me to assign an inner hash to a local reference and operate on the reference to modify the original hash?

Thanks, Matt

Note: example keys inspired by watching tonight's Monday Night Football.

Replies are listed 'Best First'.
Re: Reference/Alias inner hash section
by broomduster (Priest) on Sep 08, 2008 at 23:46 UTC
    You need:

    use strict; use warnings; use Data::Dumper; my %a; $a{'WI'}{'GreenBay'}{'Color'} = 'Black'; foreach my $update ("WI,GreenBay,White") { my ($state,$city,$color) = split /,/, $update; my $h = $a{$state}{$city}; $h->{'Color'} = $color; }; print Dumper(\%a), "\n"; __DATA__ $VAR1 = { 'WI' => { 'GreenBay' => { 'Color' => 'White' } } };

    Note that using strictures will catch your spelling error ($updtate) when you split (which is why your hash appears to be empty). Also note that $a{$state}{$city} is already a reference to your "inner hash" (i.e., a hash of hashes already uses a reference).

Re: Reference/Alias inner hash section
by ikegami (Patriarch) on Sep 08, 2008 at 23:56 UTC

    The easy problem first: You've misspelled $update. Of all times, the time use strict; and use warnings; are needed the most is when hunting bugs. Use them!!

    $h contains a reference to a scalar, the value at $a{$state}{$city}. You need to deference it before you can do anything with the referenced value.

    $a{$state}->{$city}->{Color} = $color; === ${ \( $a{$state}->{$city} ) }->{Color} = $color; # For every reference added, # a dereference must be added. === my $r = \( $a{$state}->{$city} ); ${ $r }->{Color} = $color;
      Oh fer cryin' out loud -- thanks, both of you. Try to mock up a quick stripped-down version, and I shoot myself in the foot. Thanks again, Matt

        The difference between

        # broomduster my $h = $a{$state}{$city}; $h->{'Color'} = $color;

        and

        # ikegami my $r = \( $a{$state}->{$city} ); ${ $r }->{Color} = $color;

        is that only the latter autovivifies if necessary. For example, here's what happens if

        $a{'WI'}{'GreenBay'}{'Color'} = 'Black';
        is commented out:
        # broomduster $VAR1 = { 'WI' => {} };
        # ikegami $VAR1 = { 'WI' => { 'GreenBay' => { 'Color' => 'White' } } };

        The following would also do:

        my $h = $a{$state}{$city} ||= {}; $h->{'Color'} = $color;