Dict comprehensions 🐍 are elegant 😍
But in and old tip I used it to swap keys + values of a dict:
>>> synonyms = {
... 'happy': 'content',
... 'joyful': 'content',
... 'elated': 'ecstatic',
... 'sad': 'unhappy',
... 'miserable': 'unhappy',
... 'angry': 'irate',
... 'furious': 'irate',
... 'calm': 'tranquil',
... 'serene': 'tranquil',
... 'smart': 'intelligent'
... }
>>> synonyms = {v: k for k, v in synonyms.items()}
However that's tricky if there are duplicate values. Then some original keys get "squashed" 😱
>>> from pprint import pprint as pp
>>> pp(synonyms)
{'content': 'joyful', # happy lost
'ecstatic': 'elated',
'intelligent': 'smart',
'irate': 'furious', # no more angry
'tranquil': 'serene', # calm got clobbered
'unhappy': 'miserable'} # where is sad?
In this case it's better to use a defaultdict
from the collections
module:
>>> synonyms = {
... "happy": "content",
... "joyful": "content",
... "elated": "ecstatic",
... "sad": "unhappy",
... "miserable": "unhappy",
... "angry": "irate",
... "furious": "irate",
... "calm": "tranquil",
... "serene": "tranquil",
... "smart": "intelligent"
... }
>>> from collections import defaultdict
>>> inverted_synonyms = defaultdict(list)
>>> for key, value in synonyms.items():
... inverted_synonyms[value].append(key)
...
>>> pp(inverted_synonyms)
defaultdict(<class 'list'>,
{'content': ['happy', 'joyful'],
'ecstatic': ['elated'],
'intelligent': ['smart'],
'irate': ['angry', 'furious'],
'tranquil': ['calm', 'serene'],
'unhappy': ['sad', 'miserable']})
Now all keys are preserved, no truncating happened in the process. 🎉
A defaultdict automatically initializes each new key with a default type, in this case, a list. This allows us to append multiple values to each key without overwriting them, thus preserving all the original keys when inverting the dictionary.
Additionally, defaultdict enhances code efficiency and readability. In a standard dictionary, if you're adding items to a list within a dictionary, you often need to check whether the key already exists or not. This typically involves an if statement to either initialize a new list or append to an existing one (although you can use dict's setdefault, but I think defaultdict is cleaner/ more readable).
Compare:
inverted_synonyms = {}
for key, value in synonyms.items():
if value not in inverted_synonyms:
inverted_synonyms[value] = [key]
else:
inverted_synonyms[value].append(key)
With:
from collections import defaultdict
inverted_synonyms = defaultdict(list)
for key, value in synonyms.items():
inverted_synonyms[value].append(key)
📈 😍
#defaultdict