Home > database >  Interchangeable dictionary
Interchangeable dictionary

Time:02-13

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.

  • Related