Your initial request immediately made me think of the lisp function called rassq, which operates on an alist -- which is very similar to a hash but implemented differently; because of the way Perl's hashes are implemented, forward lookups are very fast, but reverse lookups are relatively expensive (as you've discovered). With alists, forward and reverse lookups are roughly equally expensive.

It is relatively easy to implement an alist in Perl. (The following code is untested...

my @alist = ( [key1 => value1], [key2 => value2], [key3 => value3], ); sub assq { my ($alistref, $key) = @_; for (@$alistref) { return $_ if $$_[0] eq $key; # eq doesn't mean exactly the same thing as in lisp, # but don't worry about that if you don't know lisp. } } sub rassq { my ($alistref, $value) = @_; for (@$alistref) { return $_ if $$_[1] eq $value; # eq doesn't mean exactly the same thing as in lisp, # but don't worry about that if you don't know lisp. } }

If you are working with large alists, assq will be much slower than the equivalent hash lookup. You probably can improve it slightly be replacing foreach with an ugly C-style for loop.

I also don't know whether rassq will be significantly faster than doing the equivalent thing on a hash; what I do know is that it will be just as fast as assq. If you want to compare the alist rassq with the equivalent reverse hash lookup, I suggest using Benchmark. Here's the closest thing I can come up with for doing a rassq-like operation on a hash:

sub hashrassq { my ($hashref, $value) = @_; foreach (keys %$hashref) { return $_ if $$hashref{$_} eq $value; } }

Also note that there are significant differences if more than one hash key has the same value; the alist implementation will always return the first one as defined in terms of the order in which the associations were added to the list (unless you add by unshifting or similar), but the hashrassq will pick one (for practical purposes) arbitrarily. You can define an order by sorting the key list for the foreach loop, but this does not allow you to take the first one added to the hash, since hashes don't store order like that. Also note that the hash implementation may be more efficient if you iterate over the hash using each, just as the alist may be more efficient if you iterate by index. Only way to be sure is to use Benchmark.


In reply to Re: Given ref to hash value, retrieve the key by jonadab
in thread Given ref to hash value, retrieve the key by gazpacho

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.