Dictionaries
The Dictionary Data Structure
A dictionary (python type: dict) is a collection of many values that can be indexed by any object type, unlike lists that are automatically indexed by integers. Indexes for dictionaries are called keys,
and a key with its associated value is called a key-value pair. Python dictionaries use curly braces notation { key1: value1, key2: value2, ...}.
📦 A list containing names of animals ['cat', 'dog', 'hen', 'fish']
| Index | Value |
|---|---|
0 |
'cat' |
1 |
'dog' |
2 |
'hen' |
3 |
'fish' |
📦 A dictionary containing ages of three people {'john': 12, 'sara': 14.5, 'colin': 13}. john-12 is a key-value pair.
| Key | Value |
|---|---|
'john' |
12 |
'sara' |
14.5 |
'colin' |
13 |
📦 A dictionary containing details of a person {'name': 'john', 'age': 14.5, 'sex': 'F', 'citizen': True}
| Key | Value |
|---|---|
'name' |
'john' |
'age' |
14.5 |
'gender' |
'F' |
'citizen' |
True |
📦 Some examples of defining dictionaries.
friends = {} # empty dictionary
grades = {'TE3201': 'A'}
numbers = {1: 'one', 2: 'two', 3: 'three'}
is_nice = {'jane': False, 'hakim': True, 'ravi': True}
prices = {'bread': 3.5, 'butter': 5.0, 'banana': 0.15}
Unlike lists which contain an ordered sequence of items, dictionaries are not ordered i.e., we cannot force a key-value pair in a dictionary to be at a specific position e.g., in the example above, there is no guarantee that 'bread':'3.50' pair will be at the first position of the dictionary prices after adding more key-value pairs to it.
Exercise: Get Subject Info
Complete the get_subject_info function below to return a dictionary such that the code produces the given output.
def get_subject_info(code, name, level, is_core):
return {} # UPDATE THIS LINE
print(get_subject_info('TE3201', 'Software Engineering', 3, False))
print(get_subject_info('CS1101', 'Programming Basics', 1, True))
⤵️
{'code': 'TE3201', 'name': 'Software Engineering', 'level': 3, 'core?': False}
{'code': 'CS1101', 'name': 'Programming Basics', 'level': 1, 'core?': True}
def get_subject_info(code, name, level, is_core):
return {'code': code, ...}
print(get_subject_info('TE3201', 'Software Engineering', 3, False))
Working with Dictionaries
You can use keys to access values in a dictionary.
📦 Some examples of retrieving values based on the key:
|
→ |
|
📦 Examples of adding, updating, and deleting dictionary entries:
|
→ |
|
Exercise: Get, Set, Delete Score
Complete the three function below such that the code produces the given output.
Given the parameterscores is a dictionary of the format {'amy': 35, 'betty': 36, 'charlie': 30} which contains scores of a bunch of players,
get_score(scores, player): returns the value of the keyplayerset_score(scores, player, new_score): sets the value of the keyplayerto thenew_scoredelete_score(scores, player): deletes the value for keyplayer
def get_score(scores, player):
return # UPDATE HERE!
def set_score(scores, player, new_score):
pass # REPLACE THIS WITH YOUR CODE!
def delete_score(scores, player):
pass # REPLACE THIS WITH YOUR CODE!
game1_scores = {'amy': 35, 'betty': 36, 'charlie': 30}
print(get_score(game1_scores, 'betty'))
print(get_score(game1_scores, 'amy'))
set_score(game1_scores, 'charlie', 5)
set_score(game1_scores, 'dan', 0)
print(game1_scores)
delete_score(game1_scores, 'dan')
print(game1_scores)
⤵️
36
35
{'amy': 35, 'betty': 36, 'charlie': 5, 'dan': 0}
{'amy': 35, 'betty': 36, 'charlie': 5}
def get_score(scores, player):
return scores[player]
def set_score(scores, player, new_score):
scores[player] = new_score
Trying to access a value for a non-existent key raises a KeyError exception.
📦 This exampls raises an exception because the key 'santa' does not exist in the dictionary is_nice:
|
→ |
|
Exercise: Get Score with Error Handling
Update the get_score1(scores, player) function to handle error situations, as described below.
Given the parameterscores is a dictionary of the format {'amy': 35, 'betty': 36, 'charlie': 30} which contains scores of a bunch of players,
get_score1(scores, player): returns the value of the keyplayer. Returns an error message if theplayeris not inscores.
def get_score1(scores, player):
return scores[player] # UPDATE HERE!
game1_scores = {'amy': 35, 'betty': 36, 'charlie': 30}
print(get_score1(game1_scores, 'charlie'))
print(get_score1(game1_scores, 'brown'))
⤵️
30
brown is not in the game!
def get_score1(scores, player):
try:
return scores[player]
except KeyError:
...
You can use keys() and values() methods to iterate through keys and values of a dictionary, respectively.
📦 The code below shows how to iterate through keys/values of a dictionary.
|
→ |
|
|
→ |
|
You can use the sorted() function to sort the keys/values before iterating through them.
📦 The code below shows how to iterate through keys/values of a dictionary.
|
→ |
|
Exercise: Print Scorecard
Update the functions in the code to behave as described below such that the code produces the output given below the code.
Given the parameterscores is a dictionary of the format {'amy': 35, 'betty': 36, 'charlie': 30} which contains scores of a bunch of players,
get_team_score(scores): returns the total of all scores of all players inscores.print_scorecard(scores): prints scores of each player in the format given, in the alphabetical order of player names.
def get_team_score(scores):
total = 0
#ADD YOUR CODE HERE!
return total
def print_scorecard(scores):
#pass #REPLACE WITH YOUR CODE!
game2_scores = {'zac': 35, 'betty': 30, 'aaron': 10}
print_scorecard(game2_scores)
print('total =', get_team_score(game2_scores))
⤵️
aaron = 10
betty = 30
zac = 35
total = 75
for p in scores.keys():
...
for p in sorted(scores.keys()):
...
As usual, you can use in and not in to check whether a key or a value is in a dictionary.
📦 The code below shows how to check if a certain key or a value exists in a dictionary.
|
→ |
|
|
→ |
|
Exercise: Add Bonus
Update the functions in the code to behave as described below such that the code produces the output given below the code.
Given the parameterscores is a dictionary of the format {'amy': 35, 'betty': 36, 'charlie': 30} which contains scores of a bunch of players,
add_bonus(scores, player, bonus): adds thebonusto the value of theplayerif player already exists inscores. Otherwise, adds theplayertoscoreswith the valuebonus.
def add_bonus(scores, player, bonus):
pass #REPLACE WITH YOUR CODE!
game3_scores = {'amy': 35, 'betty': 36, 'charlie': 30}
add_bonus(game3_scores, 'amy', 5)
add_bonus(game3_scores, 'dan', 10)
print(game3_scores)
⤵️
{'amy': 40, 'betty': 36, 'charlie': 30, 'dan': 10}
def add_bonus(scores, player, bonus):
if player in scores.keys():
...
else:
...
Nested Dictionaries
Dictionaries and lists can be nested in each other to create more complicated data structures.
📦 This dictionary keeps track of assignments of each subject. Note how the value is a list rather than a simple value such as int or string.
assignments = {'TE3201': ['do exercises', 'submit project'],
'CS2103': [],
'CS3281': ['do presentation']}
💡 Python ignores line breaks and indentations in the middle of a dictionary/list definition. The intention is to allow you to structure the code into a more readable format (e.g., one key-value pair per line).
As the values in this dictionary are lists, you can do list operations on them, e.g., append(), len()
print('CS3281 assignments:', assignments['CS3281'])
assignments['CS3281'].append('study for exams')
print(assignments['CS3281'])
print('How many things to do in TE3201?', len(assignments['TE3201']))
# calculate total assignments
total = 0
for a in assignments.values():
total = total + len(a)
print('total tasks to do:', total)
⤵️
CS3281 assignments: ['do presentation']
['do presentation', 'study for exams']
How many things to do in TE3201? 2
total tasks to do: 4
Exercise: Inning-Scores
Assume the game has three innings and a player can play in 0-3 innings. For each inning, a player will have a inning-score which is an integer e.g., player amy scored 5, 5, and 10 for the three innings (in order).
Update the get_detailed_scores functions in the code below such that it returns a dictionary that stores inning scores of each player as a list of integers for each player. Inning-scores of each player is given below.
| Player | Scores in different innings |
|---|---|
| amy | 5, 5, 10 |
| betty | 10 |
| charile | (did not play any innings) |
def get_detailed_scores():
return {'amy': 20, 'betty': 30, 'charlie': 30} #REPLACE WITH YOUR CODE!
print(get_detailed_scores())
⤵️
{'amy': [5, 5, 10], 'betty': [10], 'charlie': []}
def get_detailed_scores():
return {'amy': [5, 5, 10],
...}
📦 This dictionary uses dictionaries as values (i.e., nesting dictionaries inside dictionaries). It stores details of a group of persons.
friends = {'john': {'name': 'John Doe', 'birthday': 'Jan 12'},
'sara': {'name': 'Sara Parker', 'birthday': 'Jun 30'},
'betty': {'name': 'Betsy Sims', 'birthday': 'Jan 12'}}
print(friends['john']['birthday'])
# print friends whose birthday is Jan 12
for f in friends.keys():
details = friends[f]
if details['birthday'] == 'Jan 12':
print(details['name'])
⤵️
Jan 12
John Doe
Betsy Sims
💡 As friends['john'] evaluates to a dictionary, you can use the ['birthday'] notation to find the birthday of that person.
friends['john']['birthday']
→ {'name': 'John Doe', 'birthday': 'Jan 12'}['birthday']
→ 'Jan 12'
Exercise: Player Stats
Assume in each inning a player gets to bat number of times and each hit can score 0, 1, 4, or 6, which are known as hit sizes. There is a need to keep track of how many times a player achieved each hit size in an inning.
Note how the player_stats dictionary in the code below uses lists which contain dictionaries to store, for each player, how many times the player scored a certain hit size, for each inning. For example, the player amy scored hit size of 0 x 0 times; hit size of 1 x 1 times; hit size of 4 x 1 times; hit size of 6 x 0 time in the first inning (which adds up to a score of 0*0 + 1*1 + 4*1 + 6*0 = 10 for her first inning).
Update the get_player_hit_count(player_stats, player, inning, hit_size) functions in the code such that it uses the player_stats dictionary to return the hit count for the player in the inning for the given hit_size.
e.g., get_player_hit_count(player_stats, 'amy', 2, 6) should return how many times amy's hits in her second inning (i.e., inning = 2) scored 6s; the
return value should be 0.
player_stats = {'amy': [{0:0, 1:1, 4:1, 6:0}, # amy's first inning stats
{0:2, 1:5, 4:0, 6:0}, # amy's second inning stats
{0:0, 1:0, 4:1, 6:1}], # amy's third inning stats
'betty': [{0:2, 1:2, 4:2, 6:0}],
'charlie': []}
def get_player_hit_count(stats, player, inning, hit_size):
return 0 #REPLACE WITH YOUR CODE!
print(get_player_hit_count(player_stats, 'amy', 2, 1))
print(get_player_hit_count(player_stats, 'betty', 1, 4))
⤵️
5
2
def get_player_hit_count(player_stats, player, inning, hit_size):
return player_stats[...][inning-1][...]
Exercise: Grade Report
Write a program that reads student grades one entry at a time and print a consolidated grade report at the end. Follow the sample output given below.
-----------------------------------------------------
~ Welcome to Grade Report System ~
* Enter one entry at a time in the format NAME GRADE
* NAME should be one word
* Enter an empty line to proceed to printing report
-----------------------------------------------------
Student name and grade? amy A
Student name and grade? ben B
Student name and grade? ben
Invalid input! Entry rejected.
Student name and grade? ben C D
Invalid input! Entry rejected.
Student name and grade? ben A
Student name and grade? charlie F
Student name and grade? amy A+
Student name and grade? amy D
Student name and grade?
============ Grade Report ===============
amy : A A+ D
ben : B A
charlie : F
- use a dictionary of this format to store grades:
{'amy': ['A', 'A+', 'D'], 'ben': ['B', 'A'], 'charlie': ['F']} - The string method
split()can be useful to break the user entry into name and grade.
As you know,'aaa bbb ccc'.split()evaluates to a list['aaa', 'bbb', 'ccc'] - The string method
join()can be useful when printing grades.
As you know,' '.join(['aaa', 'bbb', 'ccc'])evaluates to'aaa bbb ccc'