in reply to Iterate over HoH without Recursion

Very nice piece of code. However, it is actually more expensive than doing it with recursion, because you are really implementing the stack handling that recursion does, but in Perl (instead of C, in which Perl is written).

Using the code below, I get the following:

Benchmark: timing 10000 iterations of ZZamboni, chromatic... ZZamboni: 12 wallclock secs ( 5.64 usr + 0.00 sys = 5.64 CPU) chromatic: 19 wallclock secs ( 8.10 usr + 0.01 sys = 8.11 CPU)
I don't know how to benchmark memory usage of each subroutine, but that would be interesting because for a very large data structure, doing it non-recursively may actually be good in terms of memory use.

Here's the code:

#!/usr/bin/perl -w use strict; use Benchmark; my $tree = ''; my %hash = ( 1 => 1, 2 => { 3 => 4, 5 => { 6 => 7 }, }, 8 => 9, 10 => {}, ); sub ZZamboni { my %hash=%{$_[0]}; my $level=$_[1]; my $tree=''; my $key; foreach $key (sort { $a <=> $b } keys %hash) { $tree .= "\t" x $level . "$key => "; if (ref($hash{$key})) { $tree .= "\n" . ZZamboni($hash{$key}, $level+1); } else { $tree .= $hash{$key} . "\n"; } } return $tree; } sub chromatic { my %hash=%{$_[0]}; my @stack; push @stack, \%hash; my $level = 0; my $tree=''; while (@stack) { my ($hash_ref, $keys_ref); if (ref($stack[-1]) eq 'ARRAY') { ($hash_ref, $keys_ref) = @{ pop @stack }; $level--; } else { $hash_ref = pop @stack; $keys_ref = [ sort { $b <=> $a } (keys %$hash_ref) +]; } while (my $key = pop @{ $keys_ref }) { my $value = $hash_ref->{$key}; if (ref($value) eq 'HASH') { $tree .= "\t" x $level . "$key => \n"; push @stack, ([ $hash_ref, $keys_ref ], $va +lue); $level++; last; } else { $tree .= "\t" x $level . "$key => $value\n" +; # print "on key $key, stack is ", $level, " l +evels deep.\n"; } } } return $tree; } timethese(10000, { 'ZZamboni' => sub { ZZamboni(\%hash, 0) }, 'chromatic' => sub { chromatic(\%hash) }, });

--ZZamboni

Replies are listed 'Best First'.
Re^2: Iterate over HoH without Recursion
by tphyahoo (Vicar) on Nov 24, 2005 at 15:02 UTC
    ++ZZamboni. Since I can see myself reusing some variation of this, here is my version of it, which just has some stylistic changes that make it slightly easier to read (for me!).
    sub ZZamboni { my $hash = shift; my $level = shift; $level = $level ? $level : 0; my $tree=''; my $key; foreach $key (sort { $a <=> $b } keys %$hash) { $tree .= "\t" x $level . "$key => " ; if (ref($hash->{$key})) { $tree .= "\n" . ZZamboni($hash->{$key}, $level+1) ; } else { $tree .= $hash->{$key} . "\n"; } } return $tree; }