How to perform Calculations with Dictionaries in Python?

You want to perform various calculations (e.g., minimum value, maximum value, sorting, etc.) on a dictionary of data.
We will create a dictionary with tennis players and their grandslam titles.
PlayerTitles = {
   'Federer': 20,
   'Nadal': 20,
   'Djokovic': 17,
   'Murray': 3,
   'Theim' : 1,
   'Zverev': 0
}
1.We have a dictionary with player names and the grandslam titles won by each player. Now let us try to find out the player with least number of titles
#type(PlayerTitles)
print(f"Output \n*** The minimum value in the dictionary is {min(PlayerTitles)} ")
*** The minimum value in the dictionary is Djokovic
2.
This is probably not what we want because we are actually trying to perform a calculation involving the dictionary values. So let us try to fix this using the values() method of a dictionary.
print(f"Output \n*** The minimum value in the dictionary is {min(PlayerTitles.values())} ")
*** The minimum value in the dictionary is 0
3. Unfortunately, this is often not exactly what you want either. For example, you may want to know information about the corresponding keys i.e. Player name with least number of titles.
4. You can get the key corresponding to the min or max value if you supply a key function to min() and max().
print(f"Output \n***{min(PlayerTitles, key=lambda k: PlayerTitles[k])} ")
***Zverev
5. However, to get the minimum value, you’ll need to perform an extra lookup.
min_titles = PlayerTitles[min(PlayerTitles, key=lambda k: PlayerTitles[k])]
print(f"Output \n***{min_titles} ")
***0
6.
The solution involving zip() solves the problem by "inverting" the dictionary into a sequence of (value, key) pairs. When performing comparisons on such tuples, the value element is compared first, followed by the key.
This gives us exactly the behavior that we want and allows reductions and sorting to be easily performed on the dictionary contents using a single statement.
min_titles = min(zip(PlayerTitles.values(), PlayerTitles.keys()))
max_titles = max(zip(PlayerTitles.values(), PlayerTitles.keys()))

print(f"Output \n***{min_titles , max_titles} ")
***((0, 'Zverev'), (20, 'Nadal'))
7.Similarly, to rank the data, use zip() with sorted()
titles_sorted = sorted(zip(PlayerTitles.values(), PlayerTitles.keys()))
print(f"Output \n***{titles_sorted} ")
***[(0, 'Zverev'), (1, 'Theim'), (3, 'Murray'), (17, 'Djokovic'), (20, 'Federer'), (20, 'Nadal')]
8.
When doing these calculations, be aware that zip() creates an iterator that can only be consumed once.
titles_and_players = zip(PlayerTitles.values(), PlayerTitles.keys())
print(f"Output \n***{min(titles_and_players)} ")
***(0, 'Zverev')
9. If we try to call it again, we will be facing an exception as empty sequence.
10.
It should be noted that in calculations involving (value, key) pairs, the key will be used to determine the result in instances where multiple entries happen to have the same value.
For instance, in calculations such as min() and max(), the entry with the smallest or largest key will be returned if there happen to be duplicate values. That is the reason when we choose for players with maximum titles, we end up with only one value which is Nadal.(See step 7 Output).