SPUG: Slice of HashOfHash

Jacinta Richardson jarich at perltraining.com.au
Thu Nov 16 03:27:45 PST 2006

David Dyck wrote:

>> but the if statement is somewhat unsafe. in the case where the subhash
>> doesn't have a key named 'husband', it will be autovivified. this may
>> or may not be a problem.
> The above _may_ have been true at some version of perl (as I used to
> write code like below also (using exists) - but it is not now the case when
> I test the code.  I you find a perl doing this (where
>    if ( $hash->{ exhusband } eq 'fred' ) 
> autovivifies some element in %HoH), please let me know, as I couldn't
> create a test case with recent (6 year old) perl version where the
> if test needed the exists check that you gave below.

I agree that the proposed if statement doesn't cause auto-vivication, but it's 
important to be aware that it *will* cause a warning to be generated if warnings 
are turned on.  Comparing an undefined thing to a string does that.  ;)  This 
isn't a big deal but most people don't like their code generating warnings, so 
Jerry's advice (to check the field first ) is right... just for the wrong 
reason.  Of course, we can also just check it for truth and save a few characters.

My personal solution to the given problem is:

foreach my $key ( keys %HoH ) {
         if($Hoh{$key}{husband} && $HoH{$key}{husband} eq "fred") {
                 print "yes\n";

The main difference being that I don't understand why someone would recommend 
taking a hash slice of the whole hash when we can just iterate over the keys.  I 
suspect Damian Conway would suggest instead that we iterate over the values:

foreach my $value ( values %HoH ) {
         if($value->{husband} && $value->{husband} eq "fred") {
                 print "yes\n";

because he doesn't like the extra work of dereferencing when values() does the 
work for us.  It's in the PBP book which I don't have handy right now.  He's 
right, but I still prefer keys().

I think the original poster was asking whether there's a way to do something 
like this:

	foreach my $husband ( @{$HoH{ _ }{husband} ) {
		if( $husband eq "fred" ) {
			print "yes\n";

Such that Perl iterates over all the keys and pulls out the husband for each 
subhash for us.  It would be cool, I've wanted to do it myself a few times, but 
no; there's no way specifically like that.  But it's not much less code than the 
other solutions either.

All the best,


More information about the spug-list mailing list