If you want to create a slightly more flexible solution, you can recursively traverse the data tree. Consider this example data tree (arbitrary depth):
Data examples
my %people = ( memowe => { NAMES => { memo => {AGE => 666}, we => {AGE => 667}, }, }, bladepanthera => { NAMES => { blade => {AGE => 42}, panthera => {AGE => 17}, }, }, );
From your question, I came to the conclusion that you just want to work with leaves ( AGE in this case). Thus, you can write a recursive subroutine traverse that executes a given substructure on all sheets that it can find in sorted by depth in depth order. This subelement receives the vacation itself and the hash key path:
Training
sub traverse (& $@ ) { my ($do_it, $data, @path) = @_; # iterate foreach my $key (sort keys %$data) { # handle sub-tree if (ref($data->{$key}) eq 'HASH') { traverse($do_it, $data->{$key}, @path, $key); next; }
I think it's pretty clear how this guy works from inline comments. There would not be much change to execute coderef for all nodes, not just leaves, if you wanted to. Note that I excluded a prototype for this, for convenience, because it is pretty easy to use traverse with the famous map or grep syntax:
Executing data in your data
traverse { say shift . " (@_)" } \%people;
Also note that it works with hash links, and we initialized @path with an implicit empty list.
Exit
42 (bladepanthera NAMES blade AGE) 17 (bladepanthera NAMES panthera AGE) 666 (memowe NAMES memo AGE) 667 (memowe NAMES we AGE)
A given routine (written as a { block } ) can do anything with data. For example, this more readable push routine:
my @flattened_people = (); traverse { my ($thing, @path) = @_; push @flattened_people, { age => $thing, path => \@path }; } \%people;