I wish to have a dictionary that is interchangeable i.e. values are mapped with keys & keys are mapped with value so that if we know one element, the other partner can be known. In python dict, using keys, we can get values but not vice-versa. How can I achieve this? Note: For interchangeability, there has to be a 1-1 mapping between key: value & value: key.
Example:
key = {'a':'1','b':'2','c':'3'}
So, I should be able to get 1 for key['a'] & 'a' for key['1']
CodePudding user response:
Here is an example of how you might create a class to do this for you. Be aware that this is quite slow when setting new / editing existing values.
class DoubleDict:
def __init__(self, *dicts, **extras):
self.dict1 = {}
for dct in dicts:
self.dict1 |= dct
self.dict1 |= extras
self.dict2 = dict(zip(self.dict1.values(), self.dict1.keys()))
def __getitem__(self, key):
try: return self.dict1.__getitem__(key)
except KeyError: return self.dict2.__getitem__(key)
def __setitem__(self, key, value):
if key in self.dict1:
self.dict2.pop(self.dict1[key])
self.dict1.pop(key)
elif key in self.dict2:
self.dict1.pop(self.dict2[key])
self.dict2.pop(key)
if value in self.dict1:
self.dict2.pop(self.dict1[value])
self.dict1.pop(value)
elif value in self.dict2:
self.dict1.pop(self.dict2[value])
self.dict2.pop(value)
self.dict1[key] = value
self.dict2[value] = key
def __iter__(self):
total_dict = self.dict1 | self.dict2
return total_dict.__iter__()
def __repr__(self):
return f"DoubleDict({repr(self.dict1)})"
def __str__(self):
return "\n".join(f"{key} <==> {self.dict1[key]}" for key in self.dict1)
Here is how it works:
a = DoubleDict({1: 2, 3: 4, 5: 6, 7: 8})
print(a)
# 1 <==> 2
# 3 <==> 4
# 5 <==> 6
# 7 <==> 8
a[1] = 3
# Now the 3,4 pair and the 1,2 pair no longer exist, but there is a new 3,1 pair
print(a[1], a[3])
# 3 1
print(a)
# 5 <==> 6
# 7 <==> 8
# 1 <==> 3
CodePudding user response:
Assuming that there will be never collosion (i.e. keys and values are disjoint sets) then you can create "mirror" dict
then harness collections.ChainMap
as follows
import collections
key = {'a':'1','b':'2','c':'3'}
rev_key = dict(i[::-1] for i in key.items())
final = collections.ChainMap(key,rev_key)
print(final['a'])
print(final['3'])
print(final['c'])
output
1
c
3
WARNING: this solution assumes you want to use final
only for reading. It does not support reflection of value you insert (e.g. final['d'] = '4'
will NOT cause final['4']
to become 'd'
)
CodePudding user response:
One possible way to that is... you can simply updated existing dictionary as it contains all the opposite key-value pairs, as follows:
dict1 = {'a': '1','b' :'2','c': '3'}
dict2 = dict(zip(dict1.values(), dict1.keys())) # create value-key pair dictionary
dict1.update(dict2) # combining dict2 with dict1
print(dict1)
#{'a': '1', 'b': '2', 'c': '3', '1': 'a', '2': 'b', '3': 'c'}
However, you should be careful of to use this because there might be duplicated keys and values each others.