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

I have what I think is not a unique problem, just one that I cannot seem to successfully solve.

I have a hash of hashes, to N levels deep (usually around 8 to 10). Each hash has some normal hash items, and one is the one with the deep children, at each level. The deep one always has a numeral for a key, so /\d+/ works to find it.

Anyhow, I need a routine that will recurse through the hash, starting at the top, looking for a particular key number. If found, I need it to return THAT value.

I've been writing a recursive subroutine, but it seems to fail.

Here it is:
my ($newtop,$error) = _get_top($wanted_number,$tippy_top_hash); and sub _get_top { my $top_req = shift; my $top_item = shift; if ($top_item->{'ctl_id'} == $top_req) { return ($top_item,undef); } ## Added for speed if (exists($top_item->{$top_req})) { return($top_item->{$top_req},undef); } ## End added for speed foreach my $key (keys %{$top_item}) { next unless ($key =~ /^\d+/); if ($key == $top_req) { return ($top_item->{$key},undef); last; ### probably not needed } else { _get_top($top_req, $top_item->{$key}); } return (undef,"Seems we can't get the top item hash!"); } }
This is failing miserably, always returning undef,"Seems . . ."
Liberal prints to STDERR reveals that it does find the wanted hash item, but continues on below it!
If any of you geniouses out there can help, I would greatly appreciate it.

What does THIS little button do . .<Click>; "USER HAS SIGNED OFF FOR THE DAY"

Replies are listed 'Best First'.
Re: Recursing a hash
by bmcatt (Friar) on Feb 21, 2002 at 20:57 UTC
    In your recursion, you're not doing anything with the return value from the embedded _get_top. Either you need to do a return _get_top(...) or save the return value and check if that was the right one if you have the possibility of needing to descend multiple times from a node.
(jeffa) Re: Recursing a hash
by jeffa (Bishop) on Feb 22, 2002 at 09:51 UTC
    This does the trick:
    use strict; use Data::Dumper; my $h = { a => 1, b => 2, c => { d => 3, e => { f => { g => 4, h => 5, }, }, }, }; my $match; my $find = 'g'; find_me($h); print "$match\n"; sub find_me { my ($k,$v,@rest) = %{shift()}; # merlyn code ;) $match = $v if $k eq $find; find_me({@rest}) if @rest; find_me($v) if ref $v eq 'HASH'; }
    It could use some major improvements, but it should be a step in the right direction. The merlyn code I used as a reference can be found at RE: permutations?.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)