Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

getting hash key with value

by sovixi (Novice)
on Apr 16, 2008 at 00:10 UTC ( [id://680691]=perlquestion: print w/replies, xml ) Need Help??

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

O mighty Monks, Is there any chance I can find hash key by just giving it the associated value? (all data in the hash is unique: each key corresponds to different value) Thank you.

Replies are listed 'Best First'.
Re: getting hash key with value
by Fletch (Bishop) on Apr 16, 2008 at 00:17 UTC

    Given the constraint that the values are distinct, just make a reverse mapping and use that. my %vals_to_keys; @vals_to_keys{ values %src } = keys %src;

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thanks a lot!!!
Re: getting hash key with value
by tachyon-II (Chaplain) on Apr 16, 2008 at 00:23 UTC

    This will only work is the values are unique but all you need to do is create a reversed hash lookup table and use that:

    my %h = qw( 1 2 3 4 5 6 ); my %rev_h = reverse %h; use Data::Dumper; print Data::Dumper::Dumper(\%h,\%rev_h); __DATA__ $VAR1 = { '1' => '2', '3' => '4', '5' => '6' }; $VAR2 = { '6' => '5', '4' => '3', '2' => '1' };

    If you can't guarantee the values are unique then you have to iterate. Use grep:

    my @keys = grep{ $hash{$_} eq $find } keys %hash;
Re: getting hash key with value
by ysth (Canon) on Apr 16, 2008 at 02:07 UTC
Re: getting hash key with value
by GrandFather (Saint) on Apr 16, 2008 at 00:20 UTC

    Create a reverse lookup hash. Consider:

    use strict; use warnings; my %hash = (x => 1, y => 2, z => 3); my %rhash; @rhash{values %hash} = keys %hash; print $rhash{1};

    Prints:

    x

    Perl is environmentally friendly - it saves trees
Re: getting hash key with value
by oko1 (Deacon) on Apr 16, 2008 at 02:11 UTC

    In my experience, whenever I find myself with a need/question of this sort, it usually means that my data structure was incorrectly designed from the start. Often, adding another variable - an array, or a second hash, or (if the keys and the values are easily told apart) additional members in the original hash - during the data collection/aggregation part of the process takes care of the problem, and does not require doubling the space.

    If for some reason you really do need a one-to-one correspondence - that is, you have two sets of data in which you must be able to look up a corresponding member for every element - then a simple hash is probably not what you want.

    
    -- 
    Human history becomes more and more a race between education and catastrophe. -- HG Wells
    
Re: getting hash key with value
by sundialsvc4 (Abbot) on Apr 16, 2008 at 01:51 UTC

    It all depends on how many thousand entries are in your hash to begin with. If the number is reasonable and you don't do it too often, it just might be simplest and quickest (if slightly aromatic...) to just iterate through the hash sequentially. In other words, you might get away with it.

    Otherwise, you're going to have to create a reverse-hash, and each slot in that reverse-hash can contain either a single value, or an array-reference containing a list of values.

    The tradeoff, as usual, is the usual one: speed versus space. By building a reverse-hash you just at-least-doubled your storage requirement... but it's fast.

    The “brute force search” may or may not be so-bad. If the hash is very large and virtual-storage is not, then the potential exists that walking through that hash is going to trigger a slew of page-faults every time, and that's really bad. But if storage is plentiful then it's all probably sitting in real-RAM anyway and you can just blip-through all that storage at CPU-speed. So basically it comes down to the practical likelihood of page-faults.

Re: getting hash key with value (List::Pairwise)
by lodin (Hermit) on Apr 17, 2008 at 10:08 UTC

    This is trivial using List::Pairwise, even if the values aren't unique.

    use List::Pairwise 'mapp'; my %hash = ( foo => 1, bar => 2, baz => 1, bux => 0, ); my $val = $hash{foo}; my @keys = mapp { $b eq $val ? $a : () } %hash; print "@keys"; __END__ baz foo
    Even if you think that your values are unique it's sometimes a good idea to assert this:
    my ($key, @too_many) = mapp { $b eq $val ? $a : () } %hash; ! @too_many or die 'Too many ...';

    lodin

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://680691]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (2)
As of 2024-03-19 06:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found