in reply to How to tie multilevel (multidimensional) hash?

Seems like recursive tied hashes should work, and there's no other way to do it. Maybe you should post your recursive hash code.
  • Comment on Re: How to tie multilevel (multidimensional) hash?

Replies are listed 'Best First'.
My code (I can't figure out how to implicitly recurse)
by mikezone (Novice) on Feb 12, 2003 at 02:25 UTC

    Here's my driving code, test.pl. I can get it to read the second dimension on the subsequent FETCH, but can't figure out how to write the recursive routine. The only recursive way I know is if I can supply the next parameter (eg. $self->FETCH( $dimension ), or implicitly, $node->{ $dimension }, where $dimension would first be 'x' and secondly 'y'). But the hash tie() API only presents one dimension at a time. A neat thing I have learned, so far, is that for storing multidimensional hashes, that the ongoing case is that the value will be an anonymous hash, and the terminus case is that the value is a scalar.

    test.pl

    #! /users/michwong/perl/bin/perl #! /users/michwong/perl/bin/perl -d:ptkdb use lib qw( . ); use MultiHash; tie %$hash, "MultiHash"; $hash->{ x }{ y } = 10; $hash->{ x }{ y };

    Here's my module, MultiHash.pm

    MultiHash.pm

    package MultiHash; sub TIEHASH { my ($class) = map { ref || $_ } shift; my $level = shift || 0; return bless { level => $level, data => {}, }, $class; } sub FETCH { my $self = shift; my $key = shift; if( UNIVERSAL::isa( $self, 'HASH' )) { print "($self) fetching '$key': $self->{ data }{ $key }\n"; } else { print "($self) fetching '$key': $self->{ data }{ $key }\n"; } return $self->{ data }{ $key }; } sub STORE { my $self = shift; my $key = shift; my $value = shift; RECURSE_CASE: { # ===== MULTIDIMENSIONAL HASH if( UNIVERSAL::isa( $value, 'HASH' )) { if( exists $self->{ data }{ $key } ) { $self->{ data }{ $key } = $value; print "($self) storing '$value' into '$key'\n"; } else { my $node; tie %$node, "MultiHash"; $self->{ data }{ $key } = $node; print "($self) storing '$value' into '$key' with new n +ode\n"; } last RECURSE_CASE; } if( UNIVERSAL::isa( $value, 'MultiHash' )) { if( exists $self->{ data }{ $key } ) { $self->{ data }{ $key } = $value; print "($self) storing '$value' into '$key'\n"; } else { my $node; tie %$node, "MultiHash"; $self->{ data }{ $key } = $node; print "($self) storing '$value' into '$key' with new n +ode\n"; } last RECURSE_CASE; } if( UNIVERSAL::isa( $value, 'SCALAR' )) { $self->{ data }; last RECURSE_CASE; } } return $value; } sub DELETE { my $self = shift; my $key = shift } sub FIRSTKEY { my $self = shift; my $temp = keys %{ $self->{ data }}; return scalar each %{ $self->{ data }}; } sub NEXTKEY { my $self = shift; return scalar each %{ $self->{ data }}; } 1;
      You have multiple hashes, so you need to tie all of them. I think that will work. You're just using autovivification to create them in the above script. Try something like this:
      use lib qw( . ); use MultiHash; my %hash_a; my %hash_b; tie %hash_a, "MultiHash"; tie %hash_b, "MultiHash"; $hash{ x } = \%hash_b; $hash{ x }{ y } = 10; $hash{ x }{ y };

        Thanks for taking the time to help me out, perrin, I feel like I'm getting closer and closer to the answer!

        Your code is close to what I'd like to do, but it'd be best if in the process of STORE()ing creates the node and then attempts to STORE the following dimension. That is, the statement $hash{ x }{ y } = 10; does all the nested ties, automatically. One of my requirements is that I don't know how many dimensions I may have to go, and I'd hate to manually tie() every time I add a key to a hash. I hope I'm doing more than autovivifying; I'm creating nodes and tie()ing them, as well as assigning them to the parent hash. If I could then have that node call STORE() and be able to give that STORE() meaningful parameters, I'd be done. But I can't figure out how to do that.