PYTHON
Building a Bidirectional Dictionary (Two-Way Map)
Implement a bidirectional dictionary in Python, allowing efficient lookup of values by key and keys by value, useful for inverse mappings.
class BidirectionalDict:
def __init__(self, initial_dict=None):
self._forward = {}
self._backward = {}
if initial_dict:
for key, value in initial_dict.items():
self[key] = value
def __setitem__(self, key, value):
# Ensure consistency: if the key or value already exists, remove old mappings
if key in self._forward:
old_value = self._forward[key]
del self._backward[old_value]
if value in self._backward:
old_key = self._backward[value]
del self._forward[old_key]
self._forward[key] = value
self._backward[value] = key
def __getitem__(self, key):
return self._forward[key]
def get_key(self, value):
return self._backward[value]
def get(self, key, default=None):
return self._forward.get(key, default)
def get_key_safe(self, value, default=None):
return self._backward.get(value, default)
def __len__(self):
return len(self._forward)
def __contains__(self, key):
return key in self._forward
def contains_value(self, value):
return value in self._backward
def __delitem__(self, key):
value = self._forward[key]
del self._forward[key]
del self._backward[value]
def __repr__(self):
return f"BidirectionalDict({self._forward})"
# Example Usage:
id_to_name = BidirectionalDict({'user1': 'Alice', 'user2': 'Bob'})
print(f"Initial map: {id_to_name}")
id_to_name['user3'] = 'Charlie'
print(f"After adding 'user3': {id_to_name}")
print(f"Name for user1: {id_to_name['user1']}")
print(f"ID for Alice: {id_to_name.get_key('Alice')}")
# Overwriting a key
id_to_name['user1'] = 'Alicia'
print(f"After changing user1 to Alicia: {id_to_name}")
print(f"ID for Alicia: {id_to_name.get_key('Alicia')}")
print(f"ID for Alice (safe method): {id_to_name.get_key_safe('Alice')}")
# Overwriting a value (which implicitly changes the associated key)
id_to_name['user4'] = 'Charlie'
print(f"After assigning user4 to Charlie: {id_to_name}")
print(f"ID for Charlie: {id_to_name.get_key('Charlie')}")
print(f"Does it contain user3? {id_to_name.__contains__('user3')}")
How it works: A bidirectional dictionary, or two-way map, allows you to look up values using keys and also look up keys using values with similar efficiency. This custom class achieves this by internally maintaining two standard dictionaries: one for `key -> value` mappings and another for `value -> key` mappings. When an item is added, updated, or deleted, both internal dictionaries are kept in sync. This structure is highly useful in scenarios requiring efficient inverse mappings, such as translating between unique identifiers and names, or managing symmetrical relationships.