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

I have a recursive function that returns a pointer to an associative array. I've included a simple version of what I'm talking about below, and interested to see if anyone can do it cleaner. (By 'it', I don't mean count to 10, I mean write a recursive routine that returns a hash ref. where the values associated with each key are arrays.)
use strict; my $i = 0; sub Recurse { my %hash = ( 'count' => [$i++] ); my %hash2 = 10 > $i ? %{Recurse()} : (); for( keys %hash2 ) { push @{$hash{$_}}, @{$hash2{$_}}; } return \%hash; } my %test = %{Recurse()}; print join ' ', @{$test{count}};

Replies are listed 'Best First'.
Re: Hash Push
by mdillon (Priest) on Aug 16, 2000 at 02:06 UTC

    here ya go: a recursive routine that returns a hash ref. where the values associated with each key are arrays (actually, references to arrays)

    use strict; use Data::Dumper; sub Recurse { my $n = shift || 0; if ($n <= 0) { return {}; } else { my $val = [ map { $n ** $_ } (1 .. 5) ]; return { $n => $val, %{Recurse(--$n)} }; } } my $powers = Recurse(5); print Dumper($powers);
    outputs:
    $VAR1 = { '1' => [ '1', '1', '1', '1', '1' ], '2' => [ '2', '4', '8', '16', '32' ], '3' => [ '3', '9', '27', '81', '243' ], '4' => [ '4', '16', '64', '256', '1024' ], '5' => [ '5', '25', '125', '625', '3125' ] };
      There is some good code there, but it has a fatal flaw. It doesn't merge keys together. Perhaps that's my fault, I didn't point that part out. The reason the values are arrays (er, references to arrays... ) is so that the various values associated with a key can be collected (in order of collection even... hehe)

      You see?

        i'm not sure this is very easy to understand in simplified form. maybe you should post a new SOPW with more complete code.
RE: Hash Push
by merlyn (Sage) on Aug 16, 2000 at 02:39 UTC
    Why does it have to be "recursive"? That doesn't make sense. This smells like homework. {grin} In any event, something this simple would do it:
    my $hash_ref = {map { $_ => [1..$_] } 10..20 };
    There. A hash ref of arrayrefs.

    -- Randal L. Schwartz, Perl hacker

      Yes, well, er, um... ok... point taken.

      But it isn't homework, its recursive because the routine reads a file, and that file might include a pointer to another file, which I would then need to go read. That reeks of recursion. And uh, merlyn, your answer doesn't even come close.

        You're right. I didn't generate the result you wanted because I couldn't quite fathom your routine, so I fell back to trying to read your specification, and came up with what I did.

        Honest mistake. Better specification always helps.

        -- Randal L. Schwartz, Perl hacker

RE: Hash Push
by Adam (Vicar) on Aug 16, 2000 at 21:16 UTC
    I'm not sure why people fealt this question wasn't sufficiently clear, so I will expand on it. I've already written the code, I'm just trying to make it cleaner and easier to maintain by the next guy. The part that I don't like is the refrences, and I was wondering if any of the Perl Monk Gurus could enlighten me with better ways of doing this without changing the over-all structure. By that I mean the routine must be recursive, the keys are associated with arrays, not scalars, and these arrays are grown as new values are found for given keys.

    Basically I'm recursivly filling a particular data structure, and I'm looking for the cleanest way to do it.

      You're not recursively filling a recursive data structure though, so the routine should not be passing data to merge: it should either be accessing a single reference and updating in place, or accessing a global (gack!).

      For example:

      my %global_data; fill_recursively(\%global_data, 10); sub fill_recursively { my $data_href = shift; # hashref to modify my $count = shift; # what level are we push @{$data_href->{"key $_"}}, "level $count" for 1..$count; fill_recursively($data_href, $count - 1) if $count > 1; } use Data::Dumper; print Dumper(\%global_data);
      The push is accessing the global data directly. Put whatever you want in there. Does that help?

      -- Randal L. Schwartz, Perl hacker

        Hey, I like that... Could I hide the whole thing too?
        Maybe write:
        sub GetData { my %data; sub Recursive { # do stuff # push onto %data # call Recursive if appropriate } Recursive(); return \%data; } my %data = %{GetData()}; # Can this be cleaner?