Bro. Doug has asked for the wisdom of the Perl Monks concerning the following question:

Good day, Monks.

For as long as I've been writing Perl, I've felt there must be better ways to do code some of the things I usually code. I stand before you with my first question.

I'm having trouble with a simple data structure that seems to have gotten wildly out of control. It's a regular hash of keys and values, but two of the values are references to arrays.
%hash; $hash{'normal'} = "Some value" ; $hash{'list1} = [] ;
Then I use the list reference to add an unspecified number of hash references to my data structure.
push @{ $hash{'list1'} }, {keys=>values} ;

Now I can access this like so:
$foo = $hash{'list1}[0]{'key'} ;

I'm quite interested in how a PerlMonk would do this.
I'm rethinking my code base, and I need a structure like this to store data for my Tk programs. I'm currently assigning the address of the element to -textvariable options.
$widget{'foo'}=$mw->Entry(-textvariable => \$hash{'normal'}); # and for dynamicly created, repeating elements $widget{'bars'}[0]{'bar1'} = $mw->Entry( -textvariable => \$hash{'bars +'}[0]{'bar1'} ) ;

The problem gets really messy when I try to do things like:
#for storing past data (think 'back button') push @past_data, \%hash ;

I can't do this because %hash is full of references. It gives me a headache.

Any Ideas, Opinions, or Comments would be appreciated.
Bro. Doug The Inert.

Replies are listed 'Best First'.
Re: Hashes of Arrays of Hashes (sometimes of Arrays)
by DrWhy (Chaplain) on Aug 11, 2006 at 22:35 UTC
    Encapsulate. You've got complex data structures. Your code is going to be complex. You should consider hiding some of that complexity behind an Object-Oriented interface. Create a module to represent your upper level %hash, and then write accessors to get at the various pieces. For example:
    package OBJ; sub new { shift; bless {@_}, 'OBJ'; } sub normal { shift->{normal} } sub listl { my $self = shift; my $index = shift; my $key = shift; $self->{listl}[$index]{$key}; } ##### package main; my $obj = new OBJ(normal => "some text", listl => [{keys => vals}, {keys => vals}, ]); $normal = $obj->normal(); $value = $obj->listl(0,'key');
    Do note that this is a very bare bones example, with no error checking, no way to set new values for the object's various components, etc.

    --DrWhy

    "If God had meant for us to think for ourselves he would have given us brains. Oh, wait..."

      Yes. I quite like the idea, thank you. But how can I assign the refs to -textvariable in Tk? I'm thinking:
      #in the package declaration sub getref { my ($self,$index,$key) = @_ ; #and then, erm.... return \$self->{'list'}[$index]{$key} ; } #and in the Tk block: $widgets{'foo'} = $obj->getref( 0, 'bar') ;

      That would probably work, but then I need to push a copy of the object onto a list of said object. The problem becomes essentially a Tk problem. The -textvariable option points to scalar refs that are, in turn, encapsulated by the object I build to hold the code. Bleh.
      Bro. Doug The Inert.
Re: Hashes of Arrays of Hashes (sometimes of Arrays)
by rodion (Chaplain) on Aug 12, 2006 at 10:35 UTC
    There's nothing wrong with hashes of arrays of hashes. They come up often enough that we have abreviations like HoAoH. The problems come when you have no names for things along the way down into the structure. If you're stuck dealing with the whole animal every time you refer to it, then the headaches come on quickly.

    Perl provides help for getting at the intermediate level with references, so you only deal with the level you're focusing on, but when you assign to a variable, you're changing it in the larger structure. Giving names to the intermediate levels lets you explain what's going on at that level. I don't know what you're working with, but one might change

    $widget{'bars'}[0]{'bar1'} = $mw->Entry( -textvariable => \$hash{'bars +'}[0]{'bar1'} ) ;
    to someting like
    $widget_current_bar = \$widget{'bars'}[0]{'bar1'}; $source_current_bar = \$hash{'bars'}[0]{'bar1'}; $$source_current_bar = $mw->Entry( -textvariable => $source_current_ba +r)
    Often this is more clear and consice than jumping to an OO approach just to give names for intermediate levels.

    You may need an OO approach for other reasons, and the syntactic overhead for handling inheritance that an OO approach brings along may be justified on that basis, but it's important to have techniques for managing structures in any case. You may need them within your methods.

Re: Hashes of Arrays of Hashes (sometimes of Arrays)
by leocharre (Priest) on Aug 12, 2006 at 08:37 UTC
    I dunno about turning to OO for any little hash problem.

    I used to have nightmares with hashes starting out.
    A couple of things that I started doing that I think helped me out..

    If I am going to have a complex structure, I start out with an anon hash, and I stick to anonymous arrays and hashes.

    #!/usr/bin/perl -w use strict; my $house = { name => 'old bertha home', guests => [ 'greg', 'thomax', 'zeimart', 'bubba' ], structure => { rooms => [ 'foyer', 'bathroom', 'front lawn', 'kitchen'], address => '121 super road, ny, ny 12866', }, }; for ( @{$house->{guests}} ) { print "$_ is in house: ".$house->{name}; print " in the ". $house->{structure}->{rooms}->[ int(rand(3))] ."\ +n"; }

    So, now you don't have to worry when passing references to function calls, if you pass it function(\%poppa); or function(\@poppa); etc.. it's always function($poppa); ... less typing too.

    Also, name your hashes singular, always. name your arrays plural, always.

    There's also the reasoning behind not doing this: $$house{structure}{address}
    instead of this
    $house->{structure}->{address}
    And thank goodness that someone wrote a book about that kind of thing so I can go to sleep now.. my eyes.. ouch...

    Seriously, try it out. Use anonymous scalars, it may be your salvation.