note
anonymized user 468275
To avoid having one foreach per level in the hash, I would write a recursive hash traversal subroutine as in this (tested) example, which uses a single foreach in a subroutine that calls itself when it finds a hash reference instead of a value:<p><b>Update 1: </b> the point of all this is not how many times foreach is actually executed but to avoid having to <i>code</i> differently for different nesting levels of the hash.<p><b>Update 2:</b> modified to show how to make the actual processing of the hash flexible. The assignment into a flat array is just to demonstrate that all the values and none of the keys of the hash were covered. A slight change can make it do something else at each node.<p>
<b>Update 3</b>: where the code examines ref($val), it could also be adapted to process arrays within hashes, by creating an extra branch for where ref($val) eq 'ARRAY'.
<code>
#!/usr/bin/perl
use strict;
use Data::Dumper;
my %h = ();
# stick in some data at varying depths
$h{ 1}{ 2}{ 3} = 123;
$h{1}{3} = 13;
$h{2} = 2;
# this array will collect the values
my @flat = ();
hashTraverse( \%h, \@flat );
print Dumper( \@flat );
sub hashTraverse {
my ( $href, $aref ) = ( shift(), shift() );
foreach my $key ( sort keys %$href ) { # this simple example sorts the tree left-right
my $val = $href -> { $key };
if ( ref( $val ) eq 'HASH' ) {
hashTraverse( $href -> { $key }, $aref )
}
else {
push @$aref, $val;
# or instead whatever else should be done to or with the hash node
}
}
}
</code><p><b>Output:</b><p>
<code>$VAR1 = [
123,
13,
2
];</code>
<!-- Node text goes above. Div tags should contain sig only -->
<div class="pmsig"><div class="pmsig-468275">
<p><i>One world, one people</i>
</div></div>
472642
472642