Perl hash hashes hashes hashes ... is there an “easy” way to get an item at the end of a list?

I have a Perl hash hash ... about 11 or 12 elements. Please forgive me for not repeating the structure below!

Some of the levels have fixed labels, for example. 'NAMES' , 'AGES' or similar, so access to these levels is good, since I can use these labels directly, but I need to iterate over other variables that lead to some very long statements. This is an example of half of one set of loops:

 foreach my $person (sort keys %$people) { foreach my $name (sort keys %{$people->{$person}{'NAMES'}}) { foreach my $age (sort keys %{$people->{$person}{'NAMES'}{$name}{'AGES'}}) { . . . # and so on until I get to the push @list,$element; part 

This is just an example, but it follows the structure of what I have. It may be shorter to not have fixed name sections (elements in caps), but they are required for reference purposes in other places.

I tried to use elements as hashes in order to shorten it at every stage, for example for the second foreach I tried various forms:

 foreach my $name (sort keys %{$person->{'NAMES'}}) 

but it didn’t work. I'm sure I saw something similar before, so the semantics might be wrong.

I studied pages regarding Hash Hashes, links to hashes and their elements, etc. no luck. I saw examples of while each loops, but they don't seem particularly shorter or easier to implement. Maybe there is just another way to do this, and I miss the point. I wrote out the full set of foreach loops once, and it would be great if I didn't have to repeat it six more times or so.

Of course, there cannot be a "simple" way, but any help is appreciated!

+6
source share
4 answers

$person is the key to shorten all inner loops, you need to assign something:

 foreach my $person_key (sort keys %$people) { my $person = $people->{$person_key}; my $names = $person->{NAMES}; foreach my $name (sort keys %$names) { 
+6
source

You can also work with every keyword. This should definitely help.

 while( my ($person, $val1) = each(%$people) ) { while( my ($name, $val2) = each(%$val1) ) { while( my ($age, $val3) = each(%$val2) ) { print $val3->{Somekey}; 
+5
source

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; } # handle leave $do_it->($data->{$key}, @path, $key); } } 

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; 
+4
source

You can use Data :: Walk , which is the type of the :: Find file for data structures.

+4
source

All Articles