A multidimensional hash is the most flexible of Perl's nested structures. It's like building up a record that itself contains other records. At each level, you index into the hash with a string (quoted when necessary). Remember, however, that the key/value pairs in the hash won't come out in any particular order; you can use the sort function to retrieve the pairs in whatever order you like.
You can create a hash of anonymous hashes as follows:
To add another anonymous hash to %HoH, you can simply say:%HoH = ( flintstones => { husband => "fred", pal => "barney", }, jetsons => { husband => "george", wife => "jane", "his boy" => "elroy", # Key quotes needed. }, simpsons => { husband => "homer", wife => "marge", kid => "bart", }, );
$HoH{ mash } = { captain => "pierce", major => "burns", corporal => "radar", };
Here are some techniques for populating a hash of hashes. To read from a file with the following format:
you could use either of the following two loops:flintstones: husband=fred pal=barney wife=wilma pet=dino
If you have a subroutine get_family that returns a list of key/value pairs, you can use it to stuff %HoH with either of these three snippets:while ( <> ) { next unless s/^(.*?):\s*//; $who = $1; for $field ( split ) { ($key, $value) = split /=/, $field; $HoH{$who}{$key} = $value; } } while ( <> ) { next unless s/^(.*?):\s*//; $who = $1; $rec = {}; $HoH{$who} = $rec; for $field ( split ) { ($key, $value) = split /=/, $field; $rec->{$key} = $value; } }
You can append new members to an existing hash like so:for $group ( "simpsons", "jetsons", "flintstones" ) { $HoH{$group} = { get_family($group) }; } for $group ( "simpsons", "jetsons", "flintstones" ) { @members = get_family($group); $HoH{$group} = { @members }; } sub hash_families { my @ret; for $group ( @_ ) { push @ret, $group, { get_family($group) }; } return @ret; } %HoH = hash_families( "simpsons", "jetsons", "flintstones" );
%new_folks = ( wife => "wilma", pet => "dino"; ); for $what (keys %new_folks) { $HoH{flintstones}{$what} = $new_folks{$what}; }
You can set a key/value pair of a particular hash as follows:
To capitalize a particular key/value pair, apply a substitution to an element:$HoH{flintstones}{wife} = "wilma";
You can print all the families by looping through the keys of the outer hash and then looping through the keys of the inner hash:$HoH{jetsons}{'his boy'} =~ s/(\w)/\u$1/;
In very large hashes, it may be slightly faster to retrieve both keys and values at the same time using each (which precludes sorting):for $family ( keys %HoH ) { print "$family: "; for $role ( keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; }
(Unfortunately, it's the large hashes that really need to be sorted, or you'll never find what you're looking for in the printout.) You can sort the families and then the roles as follows:while ( ($family, $roles) = each %HoH ) { print "$family: "; while ( ($role, $person) = each %$roles ) { print "$role=$person "; } print "\n"; }
To sort the families by the number of members (instead of ASCIIbetically (or utf8ically)), you can use keys in a scalar context:for $family ( sort keys %HoH ) { print "$family: "; for $role ( sort keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; }
To sort the members of a family in some fixed order, you can assign ranks to each:for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) { print "$family: "; for $role ( sort keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; }
$i = 0; for ( qw(husband wife son daughter pal pet) ) { $rank{$_} = ++$i } for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) { print "$family: "; for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; }
Copyright © 2001 O'Reilly & Associates. All rights reserved.