in reply to A hash slice but not..

For a specific case, you can just use the snippet you showed, of course: $hash{a}{b}{c}='some value'; When you specify nested references like that, Perl will autovivify the references that don't already point to something. (See perlref for more on autovivification.)

If you're looking to do this with an arbitrary list, here's a subroutine that shows one way to do it:

#!/usr/local/bin/perl -w use strict; sub set_nested_value { my($href, $keys, $value) = @_; my $last_key = pop @$keys; for my $key (@$keys) { $href = $href->{$key} ||= {}; } $href->{$last_key} = $value; } my %hash; set_nested_value(\%hash, ['a' .. 'c'], 'some value'); set_nested_value(\%hash, ['a', 'b', 'd'], 'other value'); use Data::Dumper; print Dumper \%hash;
The for loop descends through the nested hashes. With the ||= operator, when there isn't already a hash reference at that level, it creates a new anonymous hash. $href is then reassigned to the next level in the nested hash.

Note that this code assumes that each key will either point to a hash reference or to a value. If you set a value first, and then try to use it as a nested hash, you'll get an error from use strict. If you set a nested hash first, and then set a value at the same level, you'll delete the entire nested hash. Error checking could be added to the sub to handle those situations gracefully.

Replies are listed 'Best First'.
Re: Re: A hash slice but not..
by extremely (Priest) on Feb 15, 2001 at 00:48 UTC
    What case does yours handle that his doesn't? Honestly, I think the elegant eval wins the prize here. Perl's autovivify doesn't have the problems you state yours has. I do rather like your array-ref style argument passing tho.

    Update: Nevermind, repeat after me kids, "eval is a four letter word". =)

    --
    $you = new YOU;
    honk() if $you->love(perl)

      The eval does not handle the keys being arbitrary data.

      I prefer the loop.

        Ack, =) The same thing I scolded him for on the $value thing. I'd likely rewrite the join with a foreach that makes $tree[0] entries and still let perl handle the autoviv.

        Update: Nevermind, repeat after me kids, "eval is a four letter word". =)

        --
        $you = new YOU;
        honk() if $you->love(perl)

      Why does mine have to handle cases that his doesn't? It's just another way to do it. Anyway I didn't see his solution until after I posted mine, because I was testing my code and revising my text.

      Still, here's a case that mine handles differently from his:

      add2hash(\%tree, 1, ('print "Hello world!\n"')); set_nested_value(\%tree, ['print "Hello world!\n"'], 1);
      ;)

      BTW, relying on Perl's autovivify (as in the eval solution) does have the same problems mine has. In the snippet: $href->{a}{b}{c} = 7; If the value of $href->{a} is a string, then Perl will treat it as a symbolic reference and an error will occur under strict refs.

      Similarly, if the value of $href->{a}{b}{c} is a reference to another hash, then the above snippet will replace that hash reference with the value 7.

      Update: On second thought, just in case someone wants to run the test case, I replaced `rm -rf *` with print "Hello world!\n". :)

Re: Re: A hash slice but not..
by smferris (Beadle) on Feb 15, 2001 at 01:32 UTC

    Gotta say.. I like this one better. 8) I've already implemented it! Thanks a bunch to all!

    Shawn M Ferris
    Oracle DBA