Perl How-To
Reversing a hash. Using references.
Sometimes you want to do a look up
by value in a key-value pair. A very simple example: KEY
= filename , VALUE = ccyy-mm-dd. Let's imagine it's retrieved daily, appended to and then kept
externally via Storable. You retrieve it back into hash %filedates (note: Storable retrieve r
eturns a hash ref):
Instead of writing:
my %datesfiles;
while (my($key, $val) = each %$filedates) {
$datesfiles{$val} = $key;
}
you can use reverse :
%datesfiles = reverse %$filedates;
Actually, all this gains you is compactness. Because, as you would expect, duplicate values wo
uld result in one or more being discarded (one would remain).
How to identify the ones with duplicate values? Easy. Forget about reverse, go back the origin
al while .. each syntax. Treat each value to be a reference to an anonymous array. Viz:
while ( my ( $key, $val ) = each %$filedates ) {
push @{ $datesfiles{$val} }, $key;
}
Printing out the results in %datesfiles :
Have key = 2006-05-09 value = cpan_starred cpan_build_list
Have key = 2006-08-19 value = bin snout a.sto GenLIST_md5s sn1
Have key = 2006-05-06 value = CPANQuickReference.pdf
Have key = 2006-01-28 value = GNUstep
Have key = 2006-07-29 value = Xterms-fun yahoo.info
The print routine used is general purpose (allow the hash value to be a scalar or reference);
also provides for setting a print limit):
use Data::Dump qw(dump);
sub prt_table {
my ( $href, $lim ) = @_;
my $prt_ctr = 1;
while ( my ( $key, $value ) = each(%$href) ) {
print "Have key = $key \t\tvalue = ";
my $rval = ref $value;
if ( !$rval ) { # Not a reference, treat as scalar.
print "$value\n";
}
elsif ( $rval eq 'ARRAY' ) {
print "@{$value}\n";
}
#elsif {$rval eq 'HASH') {
# do something else
#}
else {
print "ref type $rval:" . dump($value) . "\n";
}
$prt_ctr++;
last if ( ( $lim > 0 ) && ( $prt_ctr > $lim ) );
}
print "\n";
}
#Call the print routine.
prt_table( \%datesfiles, 5 );
--
JohnIngersoll - 26 Aug 2008