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

I can't come up with a good title or search parameter for this, so if there's a node with the info I'm looking for available, please accept my apologies and point it out with a bare minimum of flaming ;)

I have many arrays like the following one, although the number of elements is completely unlimited each time : ( 'foo' , 'bar' , 'baz' )

I want to create a hash structure such that every array populates the hash like so : $hash{ 'foo' }{ 'bar' }{ 'baz' }

This is proving to be a frustratingly complex concept for what's really a piddling little detail. But of course now that I've stumbled across the issue, I can't do any "real" work until I figure it out. I've tried using references to solve it, but that seems to be failing me.

Replies are listed 'Best First'.
Re: From: array To: complex hash
by dreadpiratepeter (Priest) on Jul 07, 2003 at 17:10 UTC
    my @list=qw(a b c d e f g); my %hash; my $hptr=\%hash; $hptr = $hptr->{$_}={} foreach @list;
    This will work. the innermost key will point to an empty hashref.

    -pete
    "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."

      This will work. the innermost key will point to an empty hashref.

      Except it will clobber already existing keys/subhashes.

      my @list=qw(a b c d e f g); my %hash; my $hptr=\%hash; $hptr = $hptr->{$_}||={} foreach @list;

      Change that assignment to ||= and it works fine. :-)


      ---
      demerphq

      <Elian> And I do take a kind of perverse pleasure in having an OO assembly language...
      Thanks pete, that seems to be just what I'm looking for. In an attempt to further my own knowledge while unfortunately looking like a complete newb at this perl stuff, is there any way I can con you into explaining how you arrived at that particular solution?

      Thanks to everyone else's input... it's appreciated.
        I know that each element in the list is going to be a pointer to the one before it. I just save off a reference to where the next insertion should take place. Each time through I create a anonymous hash, insert it into the current hash (the key is the array element, the value is the anonymous hash) and store out a reference to the new hash for the next time through the loop.

        Hope that's clear. I'm much better at writing the code than explaining it in english.

        -pete
        "Worry is like a rocking chair. It gives you something to do, but it doesn't get you anywhere."
•Re: From: array To: complex hash
by merlyn (Sage) on Jul 07, 2003 at 17:22 UTC
Re: From: array To: complex hash
by argggh (Monk) on Jul 07, 2003 at 18:19 UTC
    I'll take the opportunity to plug reduce again:
    use List::Util qw(reduce); use Data::Dumper; my @c = (1, 2, 3, 4); my %d; reduce { $a->{$b} ||= {} } \%d, @c; print Dumper \%d;
    yields:
    $VAR1 = { '1' => { '2' => { '3' => { '4' => {} } } } };
    If the value of the terminating key needs to be something else than {}:
    (reduce { $a->{$b} ||= {} } \%d, @c[0..$#c-1])->{$c[$#c]} = 42; print Dumper \%d;
    which is slightly uglier, but will yield:
    $VAR1 = { '1' => { '2' => { '3' => { '4' => 42 } } } };
Re: From: array To: complex hash
by hardburn (Abbot) on Jul 07, 2003 at 17:04 UTC

    Perhaps this:

    my %hash = map { $_->[0] => { $_->[1] => { $_->[2] => 1 } } } \@array1 +, \@array2, . . . \@arrayN;

    Should work if each array only has three elements. I'm not sure how to do it for a varying number of elements, but I'll think about it. Thanks for posting an interesting question :)

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: From: array To: complex hash
by tcf22 (Priest) on Jul 07, 2003 at 17:19 UTC
    How about something like this.
    use Data::Dumper; my @array1 = ('foo', 'bar', 'baz'); my @array2 = ('foo2', 'bar2', 'baz3'); my $hashref = {}; foreach my $a(\@array1, \@array2){ my $tmpref = $hashref; foreach my $k(@$a){ $tmpref->{$k} = {}; $tmpref = $tmpref->{$k}; } } print Dumper $hashref; __OUTPUT__ $VAR1 = { 'foo2' => { 'bar2' => { 'baz3' => {} } }, 'foo' => { 'bar' => { 'baz' => {} } } };
Re: From: array To: complex hash
by MZSanford (Curate) on Jul 07, 2003 at 17:10 UTC
    I faced this working on Image::OrgChart, and came up with a really ugly solution using eval. I assume someone else will reply with a better way to do it, but if not you may want to take a gander at that.
    from the frivolous to the serious
Re: From: array To: complex hash
by bsb (Priest) on Jul 08, 2003 at 08:38 UTC