BengalsRock has asked for the wisdom of the Perl Monks concerning the following question:

$sandwichHash{cheeseburger}=burger; $sandwichHash{doubhecheeseburger}=burger;
I want to find out all of the keys that point to burger in the hash. Or if more than one exists... Any ideeas? What is the one to many rule that applies to perl hashes? Thank you humbly in advance oh great ones :-)

Replies are listed 'Best First'.
Re: One to many hash question
by jettero (Monsignor) on May 06, 2008 at 18:07 UTC
    I'd probably use grep. There are other choices.
    my @afflicted_keys = grep { $myhash{$_} eq "something" } keys %myhas +h;

    -Paul

Re: One to many hash question
by dragonchild (Archbishop) on May 06, 2008 at 18:10 UTC
    If you just want a specific one, then jettero's solution is good. If you anticipate many of these lookups, creating a reverse hash may be useful.
    my %reverse; push @{ $reverse{ $sandwichHash{$_} } }, $_ for keys %sandwichHash; print "@{ $reverse{'burger'} }\n"; print "@{ $reverse{'panini'} }\n"; print "@{ $reverse{'hoagie'} }\n";

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: One to many hash question
by apl (Monsignor) on May 06, 2008 at 18:34 UTC
    foreach my $type ( keys %sandwichHash ) { print "Sandwich $type\n" if $sandwichHash{$type} eq 'burger'; }
      Thanks, I was just hoping that there was some way to get information if exists returned more than one value without having to traverse the hash for every comparison....

      Writing code is an artform

        You can't, unless you create a reverse lookup as dragonchild suggests. Consider:

        use strict; use warnings; use Data::Dump::Streamer; my %hash = ( doubleCheeseBurger => 'burger', cheeseBurger => 'burger', cheeseSandwich => 'sandwich', tomatoSandwich => 'sandwich', ); my %rHash; push @{$rHash{$hash{$_}}}, $_ for keys %hash; Dump (\%hash, \%rHash);

        Prints:

        $HASH1 = { cheeseBurger => 'burger', cheeseSandwich => 'sandwich', doubleCheeseBurger => 'burger', tomatoSandwich => 'sandwich' }; $HASH2 = { burger => [ 'cheeseBurger', 'doubleCheeseBurger' ], sandwich => [ 'cheeseSandwich', 'tomatoSandwich' ] };

        Note that the reverse lookup hash has a list of entries for each key because of the many to one mappings in the original hash.


        Perl is environmentally friendly - it saves trees
Re: One to many hash question
by locked_user sundialsvc4 (Abbot) on May 07, 2008 at 02:54 UTC

    Nope. Sorry.

    A hash is “one-to-one” by nature. One hash-key leads to one result (which, of course, might be a list...) or to nothing. Them's your choices.

    If you need to do a reverse lookup, you have a “you decide” decision to make:   what seems most appropriate for you, in this situation?

    If you have large hashes and/or if you do these reverse lookups quite often, it might well be perfectly justifiable to maintain two hashes. The hash that's designed for reverse lookups would of course contain “a reference to a list” as its hash-target.

    On the other hand, you might decide that in your case it's acceptable or even preferable to iterate through all the keys in the hash, examining the values one-by-one.

    Bottom line is... “oh esteemed Software Designer, it's your choice, and yours alone. That's why they pay you the Big Bucks.” ;-)