in reply to Initializing Hashes of Hashes (of Hashes)

I won't debate the logic of what your doing. I did something along the same lines for an embedded language where I didn't care about "strictness" of variable references. Though you may want to reconsider.

The code below expects that keys components m/\.\d+\./ are array indexes. Letter keys are hash keys. Beware that perl arrays are not sparse so a.1000000000.f might ruin your day so $MAX_ARRAY_INDEX sets an upper limit. Beware that if a.b.c is a hash and you then say a.b.1, this will happily discard that hash at a.b.c and created an array at a.b

This was written in haste and from memory so user beware, also your example would have to chance slightly. a.b.c values would have to become a.b.c.1,a.b.c.2 etc. or just assign at once getset_key(\%form,'a.b.c',\@values).

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %form = ( a=>5,); print Dumper (\%form); print get_key(\%form,'a.b.c'),"\n" ; # Doesn't vivify print Dumper (\%form); getset_key(\%form,'a.b.c', 55); # Set $form{a}{b}{c} to 55 print Dumper (\%form); getset_key(\%form,'a.a.c.d', "umkay"); #Set $form{a}{a}{c}{d} to umkay print Dumper (\%form); getset_key(\%form,'a.b.c.d', 15); #Set $form{a}{b}{c}{d} to 15, bye c= +55! print Dumper (\%form); getset_key(\%form,'a.b.1', 100); # Sets $form{a}{b}[1] = 100 print Dumper (\%form); getset_key(\%form,'a.b.11111111', 10); # Array too big, bails print Dumper (\%form); BEGIN { my $MAX_ARRAY_INDEX = 100; sub get_key { # Does not vivify non existant keys my $h = shift; my $k = shift; die "You need to pass a reference to get_key!" unless ref($h); die "No key specified!" unless defined $k; my @p = split(/\./,$k); die "An index is too big!: ".join(', ',@p) if grep { $_=~m/^\d+ +$/ && $_ > $MAX_ARRAY_INDEX} @p; my $v = get_avhv($h,@p); } sub getset_key { # Does vivify non existant keys my $h = shift; my $k = shift; my $v = shift; die "You need to pass a reference to get_key!" unless ref($h); die "No key specified!" unless defined $k; my @p = split(/\./,$k); die "An index is too big!: ".join(', ',@p) if grep { $_=~m/^\d+$ +/ and $_ > $MAX_ARRAY_INDEX} @p; vivify_avhv($h,@p,$v); } sub vivify_avhv { my $h = \shift; my $v = pop; local $_; while (@_){ if ($_[0]=~/^\d+$/){ $$h = [] unless UNIVERSAL::isa( $$h, "ARRAY" ); $h = \$$h->[shift ()]; }else{ $$h = { } unless UNIVERSAL::isa( $$h, "HASH" ); $h = \$$h->{shift()}; } } $$h = $v; return $h; } ################################################# sub get_avhv { my $h = \shift; local $_; while (@_){ if ($_[0]=~/^\d+$/){ return unless UNIVERSAL::isa( $$h, "ARRAY" ); return if $_[0] >= @{$$h} ; # Prevent autoviv $h = \$$h->[shift ()]; }else{ return unless UNIVERSAL::isa( $$h, "HASH" ); return if ! exists $$h->{$_[0]}; # Prevent autoviv $h = \$$h->{shift()}; } } return $$h; } }


-Lee

"To be civilized is to deny one's nature."