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

Fellow monks,

References are not my strongest point and so I'm trying to increase my knowledge about them. I'm stumped on why the following bit of code is misbehaving. I'm trying to recursively traverse the hash of arrays using the elements of the array in {start} as the keys to access the succesive elements.

#!/usr/bin/perl use strict; my %found = ( start => ["a", "b", "d", "g"], a => ["c","e"], b => [], c => ["f"], d => ["e"], e => [], f => [], g => [], ); print_tree('start', ''); sub print_tree{ my ($sub, $tab) = @_; foreach (@{$found{$sub}}){ print "$tab$found{$sub}[$_]\n"; $tab .= "\t"; print_tree($found{$sub}[$_], $tab); } }

The problem is that when I run it, I get the following output:

> Executing: C:\PROGRAM FILES\CONTEXT\ConExec.exe "c:\perl\bin\perl.ex +e" "subtest.pl" a c f c f a c f c f a c f c f a c f c f > Execution finished.

Where as I'm expecting:

a c f e b d e g

I did try to use a return outside my foreach loop but it still won't traverse the initial hash key's array. Can someone please shed some light on where I've gone wrong?

In addition, why isn't the $tab being pushed locally and returned? It seems that it keeps being added to, causing the spacing to go astray.

Thanks in advance!

There is no emoticon for what I'm feeling now.

Replies are listed 'Best First'.
•Re: Recursing through hash of arrays
by merlyn (Sage) on Jun 24, 2003 at 17:57 UTC
    These two lines are at odds:
    foreach (@{$found{$sub}}){ print "$tab$found{$sub}[$_]\n";
    $_ in the foreach contains the elements, like "a" and "c", but you're using it like an index, like 0, 1, 2. Either walk the index, or walk the list, but not both.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      Thank you for that! At least I was on the right track with it all. And I think I'm beginning to understand a bit more about references. Just haven't got to that chapter of your book yet. :)

      One other thing though. I've changed the subroutine code as you suggested to:

      sub print_tree{ my ($sub, $tab) = @_; foreach (@{$found{$sub}}){ print "$tab$_\n"; $tab .= "\t"; print_tree($_, $tab); } return; }

      but the spacing is still one tab off after the first run through.

      I get:

      a c f e b etc...

      instead of:

      a c f e b etc...

      Any idea on why the $tab variable isn't resetting itself when the recursion starts coming back up it's chain? The e should be in the same column position as c.

      Thanks!

      There is no emoticon for what I'm feeling now.

        Any idea on why the $tab variable isn't resetting itself when the recursion starts coming back up it's chain?
        Yeah, you're messing with $tab in the caller, not the callee. Stop that! Don't append to the value of $tab - simply pass a different value:
        print_tree($_, "\t$tab");

        -- Randal L. Schwartz, Perl hacker
        Be sure to read my standard disclaimer if this is a reply.

Re: Recursing through hash of arrays
by LanceDeeply (Chaplain) on Jun 24, 2003 at 18:14 UTC
    since references aren't your strongest point, try explicitly assigning variables to them. it really helps to get a feel of what's going on...
    sub print_tree { my $key = shift; my $tab = shift; print "$tab$key\n"; my $array_ref = $found{$key}; if ($array_ref) { $tab .= "\t"; foreach my $element (@{$array_ref}) { print_tree($element,$tab); } } } __DATA__ output: start a c f e b d e g