A multidimensional hash is the most flexible of Perl's nestedstructures. It's like building up a record that itself contains otherrecords. At each level, you index into the hash with a string (quotedwhen necessary). Remember, however, that the key/value pairs in thehash won't come out in any particular order; you can use the sortfunction 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 froma 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 ofkey/value pairs, you can use it to stuff %HoH with either ofthese 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 toan element:$HoH{flintstones}{wife} = "wilma";
You can print all the families by looping through the keys of theouter 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 bothkeys 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, oryou'll never find what you're looking for in the printout.) You cansort 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 ofASCIIbetically (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 assignranks 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"; }
参考:http://docstore.mik.ua/orelly/perl/prog3/ch09_04.htm