Solution 1: Fast and Dirty
Here's a trivial implementation built on top of bidict , made by adrin and Austin :
class couple ( bidict ) : self._flags = {} def add ( self, key, val, flag ) : try : del self._flags[ self._inv[ val ] ] except KeyError : pass self._put(key, val, overwrite_key=True, overwrite_val=True) self._flags[ key ] = flag def flag ( self, key, val ) : if ( self._fwd.get( key ) == val ) : return self._flags[ key ] else : raise KeyError( key, val )
Thus, you can get the following behavior:
bbt = couple() bbt.add( 'stephen', 'amy', 0.4 ) bbt.flag( 'stephen', 'amy' ) >> 0.4 bbt.add( 'sheldon', 'amy', 1.0 ) bbt.flag( 'sheldon', 'amy' ) >> 1.0 bbt.flag( 'stephen', 'amy' ) >> KeyError: ('stephen', 'amy')
Solution 2: Concrete and Autonomous
Since I finally finished coding my own structure. This is standalone, and can be c / c , if necessary, someone passing here:
class FlaggedDoubleMapper : """Flagged Double Mapper""" def __init__ ( self, keys = [], vals = [], flags = [] ) : """Initializes a flagged double mapper with lists of keys, values and flags. """ self._flg = {} # Flags dictionary self._fwd = {} # Forward dictionary self._bwd = {} # Backward dictionary for key, val, flag in zip( keys, vals, flags ) : self.add( key, val, flag ) def __repr__ ( self ) : """Representation bidict-style.""" return 'fdm({})'.format( self._fwd ) def contains ( self, key, val ) : """Returns True if and only if self contains the key-val binding.""" try : return ( self._fwd[ key ] == val ) except KeyError : return False def add ( self, key, val, flag ) : """Adds a flagged binding, overwriting all corresponding bindings.""" try : _val = self._fwd[ key ] del self._bwd[ _val ] except KeyError : pass try : _key = self._bwd[ val ] del self._flg[ _key ] del self._fwd[ _key ] except KeyError : pass self._flg[ key ] = flag self._fwd[ key ] = val self._bwd[ val ] = key def remove ( self, key, *args ) : """Removes a binding. - remove( key ) will send a KeyError( key ) if no binding with key as a forward key is found. - remove( key, val ) will send a KeyError( key, val ) if no forward key-val binding is found. """ try : _val = args[0] if ( _val != self._fwd[ key ] ) : # Can raise a KeyError( key ) raise KeyError( key, _val ) except IndexError : _val = self._fwd[ key ] # Can raise a KeyError( key ) del self._flg[ key ] del self._fwd[ key ] del self._bwd[ _val ] def flag ( self, key, *args ) : """Returns the flag of a binding. - flag( key ) will send a KeyError( key ) if no binding with key as a forward key is found. - flag( key, val ) will send a KeyError( key, val ) if no forward key-val binding is found. """ try : _val = args[0] if ( _val != self._fwd[ key ] ) : # Can raise a KeyError( key ) raise KeyError( key, _val ) except IndexError : pass return self._flg[ key ]