FiniWiki, Powered by Foswiki Free and Open Source Wiki
RichmondPM > PerlHowTo
FiniWiki webs: Main | System | Sandbox   Login or Register
Users | Groups | Offices | Changes | Index | Search | Go

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

Parents: WebHome
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding FiniWiki? Send feedback