Dual look-up on keys?

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Mar 6 11:30:09 CET 2008


On Thu, 06 Mar 2008 08:37:07 +0000, Bryan Olson wrote:

> Grant Edwards wrote:
>> It may be  obvious that he has a question.  It's not the least bit
>> obvious what that question is.
> 
> How can we efficiently implement an abstract data type, call it
> 'DoubleDict', where the state of a DoubleDict is a binary relation, that
> is, a set of pairs (x, y); and the operations on a DoubleDict are those
> on a Python set, plus:
> 
>      find_by_first(self, x):  return [y where (x, y) in DoubleDict]
> 
>      find_by_second(self, y):  return [x where (x, y) in DoubleDict]
> 
> 
> Python can implement this ADT directly as specified, but the find_by_
> operations would run in time len(self).  We want an implementation where
> the find_by's run in O(1 + k) where k is the length of the returned
> sequence.

If I've understood you correctly, what you want is a reverse lookup dict. 
Here's a Quick & Dirty partial implementation to get you started. It's 
VERY simple-minded, and barely tested at all. But both lookup and reverse-
lookup should be almost as efficient as Python dicts, and it only uses 
roughly twice as many pointers as a regular dict.


class RLdict(object):
    def __init__(self, **items):
        self.D = {}
        self.R = {}
        for key, value in items.iteritems():
            self[key] = value
    def __getitem__(self, key):
        return self.D[key]
    def getkey(self, value):
        return self.R[value]
    def __setitem__(self, key, value):
        self.D[key] = value
        self.R[value] = key
    def __repr__(self):
        return "RLdict(%s)" % self.D


And in action:

>>> d = RLdict(a=1, b=2, c=3, d=4)
>>> d
RLdict({'a': 1, 'c': 3, 'b': 2, 'd': 4})
>>> d['b']
2
>>> d.getkey(2)
'b'


Naturally both the keys and values must be hashable. The version above 
makes keys/values a one-to-one mapping; if you want many-to-many, you'll 
need something more clever.

It's also possible that inheriting from dict instead of object would give 
you a whole lot of extra functionality for free, but I haven't explored 
that avenue.


-- 
Steven



More information about the Python-list mailing list