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
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |