A club counted these votes: blue, gold, blue, green, blue, gold. Which option won, and by how many votes? A plain list keeps every vote, but it does not give each option a labelled total.
By Lesson 3, you will build a tally from the list and report the winner.
You will learn
- Make a dictionary that connects each key to a value.
- Read, add, and update values by key, and use
getwhen a key may be missing. - Loop through keys or key and value pairs.
- Build a count for each choice and find the choice with the largest count.
Lesson 1: Key/Value Maps
Give each value a key
A dictionary stores key/value pairs. Each key is a label that leads to one value. Curly braces make a dictionary, and a colon separates each key from its value. The braces {} make the empty dictionary, which has no key/value pairs yet.
vote_counts = {"blue": 3, "gold": 2, "green": 1}
print(vote_counts)
Output
{'blue': 3, 'gold': 2, 'green': 1}Notice
Each label has one stored count; the braces hold the pairs.
Read one stored value by putting its key inside square brackets.
print(vote_counts["blue"])
Output
3Notice
The key "blue" finds its count, 3.
A function can use the same lookup and return the count to its caller.
def blue_vote_count():
vote_counts = {"blue": 3, "gold": 2, "green": 1}
return vote_counts["blue"]
print(blue_vote_count())
Output
3The function returns 3. A dictionary literal can hold lookup information for prices, scores, codes, and tallies.
Membership checks keys
The expression key in d tests whether key is one of dictionary d's keys, not its values. This is different from asking whether a value appears anywhere in the dictionary.
def has_medal(medals, color):
return color in medals
medal_counts = {"gold": 2, "silver": 4}
print(has_medal(medal_counts, "gold"))
print(has_medal(medal_counts, "bronze"))
print(2 in medal_counts)
Output
True
False
FalseThe calls print True, False, then False. The value 2 is stored in medal_counts, but 2 in medal_counts is false because membership checks keys.
The missing-key trap
Square-bracket access expects the key to exist. If the dictionary has no "bronze" key, this expression cannot find a value:
medal_counts["bronze"]
Python would report this traceback. It is shown as text so the lesson cell does not raise an error.
Traceback (most recent call last):
...
KeyError: 'bronze'
Read the final line first: it names the missing key.
Read safely with get
d.get(key, default) returns the key's value when the key exists. Otherwise it returns the default. It does not add the missing key.
def medal_count(medals, color):
return medals.get(color, 0)
medal_counts = {"gold": 2, "silver": 4}
print(medal_count(medal_counts, "silver"))
print(medal_count(medal_counts, "bronze"))
Output
4
0The calls return 4 and 0. Use square brackets when a key must exist. Use get when a sensible default handles a missing key.
Add or update a pair
Assignment through a key stores a value. d[key] = value adds a new pair when the key is missing and updates the old value when the key already exists.
def set_supply(item, amount):
supplies = {"markers": 6}
supplies[item] = amount
return supplies
print(set_supply("paper", 25))
print(set_supply("markers", 10))
Output
{'markers': 6, 'paper': 25}
{'markers': 10}The first call adds "paper". The second call updates "markers" from 6 to 10. Meaningful names make both the key and the stored value clear.
The next cell shows how to increase a count already stored under a key.
counts = {"blue": 3}
counts["blue"] = counts["blue"] + 1
print(counts)
Output
{'blue': 4}Notice
The old value is read before the new value, 4, is stored.
A lookup table
A lookup table turns a familiar label into useful information. The function's parameter supplies the key; the return statement sends its value back. Dictionary keys can be numbers, not only strings. In points[level], the integer in level looks up the matching integer key.
def roman_value(symbol):
values = {"I": 1, "V": 5, "X": 10}
return values[symbol]
def level_points(level):
points = {1: 10, 2: 20, 3: 30}
return points[level]
print(roman_value("I"))
print(roman_value("X"))
print(level_points(2))
Output
1
10
20A real program can read one Roman symbol and use the lookup table from this lesson.
Try it yourself
symbol = input("Roman symbol (I, V, or X): ")
print(roman_value(symbol))
Notice
The typed symbol becomes the dictionary key; you can try another symbol when you run this cell.
Lesson 2: Loop over a Dictionary
A scoreboard has several labelled values. Loops let one function visit every entry without naming the players one at a time.
Loop through the keys
for key in d visits each key. Use d[key] inside the loop to read that key's value.
def total_using_keys(scores):
total = 0
for player in scores:
total = total + scores[player]
return total
print(total_using_keys({"Nia": 8, "Omar": 11, "Paz": 6}))
Output
25The call returns 25. On each loop trip, player holds one key and scores[player] reads its integer score.
A dictionary remembers the order in which new keys were added. Try adding three keys in order.
order = {}
order["zinc"] = 1
order["iron"] = 2
order["neon"] = 3
for key in order:
print(key)
Output
zinc
iron
neonNotice
The keys print as zinc, iron, neon, in their first-added order.
Loop through key/value pairs
d.items() provides each key together with its value. The loop header has two loop names, one per pair: the first receives the key, and the second receives the value. This is the dictionary-loop form, not an assignment statement.
def print_scores(scores):
for player, score in scores.items():
print(f"{player}: {score}")
print_scores({"Nia": 8, "Omar": 11})
Output
Nia: 8
Omar: 11The equivalent one-name form is also fine:
for player in scores:
score = scores[player]
print(f"{player}: {score}")
Both forms visit the same entries. Use the form that makes the job easiest to read.
Ask for keys or values
d.keys() provides the keys. d.values() provides the values. You can loop over either one directly.
def show_score_parts(scores):
for player in scores.keys():
print(player)
for score in scores.values():
print(score)
show_score_parts({"Nia": 8, "Omar": 11})
Output
Nia
Omar
8
11Small built-in helpers
len(d) counts key/value pairs. sum(d.values()) totals numeric values. max(d.values()) returns the largest numeric value. These tools answer questions about values, but they do not tell you which key owns an extreme value.
def score_summary(scores):
print(f"players: {len(scores)}")
print(f"total: {sum(scores.values())}")
return max(scores.values())
print(score_summary({"Nia": 8, "Omar": 11, "Paz": 6}))
Output
players: 3
total: 25
11Find the key with the largest value
To return the winning key, carry both the best key and best value seen so far. The input below is non-empty and has a unique largest count.
def most_common(counts):
best_key = ""
best_count = -1
for key, count in counts.items():
if count > best_count:
best_key = key
best_count = count
return best_key
print(most_common({"blue": 3, "gold": 2, "green": 1}))
Output
blueThe strict > comparison replaces the leader only when a larger count appears. For a tie, the first tied key visited wins. A specification should promise a unique maximum or state this first-key tie rule.
A real scoreboard can read a row count followed by that many name score lines, then total the scores.
Try it yourself
n = int(input("How many players? "))
scores = {}
for i in range(n):
parts = input("Name and score: ").split()
scores[parts[0]] = int(parts[1])
print(total_using_keys(scores))
Notice
Each row adds a named score before the keys loop computes the total.
Lesson 3: Build Maps from Data
The real power of a dictionary appears when a loop builds the labelled values from raw data.
Build a frequency map
Start with an empty dictionary. For each word, make a lowercase key. If that key already exists, add 1 to its integer count. Otherwise create the key with count 1. This missing-key if/else pattern is the primary tally pattern.
def tally_words(words):
counts = {}
for word in words:
key = word.lower()
if key in counts:
counts[key] = counts[key] + 1
else:
counts[key] = 1
return counts
print(tally_words(["Sun", "rain", "sun", "SUN"]))
Output
{'sun': 3, 'rain': 1}The call returns {'sun': 3, 'rain': 1}. The .lower() call makes differently capitalized versions share one key. Each stored count is an integer.
The same missing-key pattern can count characters in one word, one letter at a time.
letters = {}
for ch in "melon":
if ch in letters:
letters[ch] = letters[ch] + 1
else:
letters[ch] = 1
print(letters)
Output
{'m': 1, 'e': 1, 'l': 1, 'o': 1, 'n': 1}Notice
melon has five different letters, so each stored count is 1.
The get shortcut
After you understand the explicit missing-key pattern, get can express the same update in one assignment. A missing key contributes the default count 0 before 1 is added.
def tally_with_get(words):
counts = {}
for word in words:
key = word.lower()
counts[key] = counts.get(key, 0) + 1
return counts
print(tally_with_get(["Echo", "echo", "drum"]))
Output
{'echo': 2, 'drum': 1}Two dictionaries compare equal when they hold the same key/value pairs, even if the pairs were added in a different order.
print(tally_with_get(["a", "b"]) == {"b": 1, "a": 1})
Output
TrueNotice
The comparison prints True; pair order does not change dictionary equality.
Group words by first letter
A dictionary value can be a list. Read word[0] to get the first character. Existing groups receive .append(word); a missing group starts with a one-word list.
def group_by_first(words):
groups = {}
for word in words:
letter = word[0]
if letter in groups:
groups[letter].append(word)
else:
groups[letter] = [word]
return groups
print(group_by_first(["map", "moon", "sun", "mist"]))
Output
{'m': ['map', 'moon', 'mist'], 's': ['sun']}The call returns {'m': ['map', 'moon', 'mist'], 's': ['sun']}. Each list keeps its words in input order. For this pattern, every input word must be non-empty.
Use the explicit membership form above. Correct: store [word] in groups[letter] for a new letter, then append to groups[letter] when that letter appears again. Wrong: appending to a fresh list returned by groups.get(letter, []) when the letter is missing changes that separate list but never stores the new key in groups.
Make a sorted leaderboard
A list may hold other lists, as in Unit 10's grids; each two-item inner list is one row. When .sort() compares two rows, it compares their first items first, so the scores decide the order. The second item only breaks ties, which the samples in this lesson avoid.
def leaderboard(scores):
board = []
for name, score in scores.items():
board.append([score, name])
board.sort()
return board
print(leaderboard({"Ari": 12, "Bea": 7, "Chen": 15}))
Output
[[7, 'Bea'], [12, 'Ari'], [15, 'Chen']]The returned leaderboard is [[7, 'Bea'], [12, 'Ari'], [15, 'Chen']]. The loop builds the list one row at a time — each row is added with append.
Filter keys into a list
Sometimes the result should contain only keys whose values pass a test. Start an empty list, test each pair, then append a passing key.
def keys_at_least(scores, minimum):
passing = []
for name, score in scores.items():
if score >= minimum:
passing.append(name)
return passing
print(keys_at_least({"Ari": 12, "Bea": 7, "Chen": 15}, 10))
Output
['Ari', 'Chen']Read records
A record line can carry a name and a number. Split it, convert the number, then store the pair.
scores = {}
record = "Rin 12"
parts = record.split()
scores[parts[0]] = int(parts[1])
print(scores)
Output
{'Rin': 12}Notice
The first piece becomes a key, and the converted second piece becomes its integer value.
For word input, split one typed line and update a tally for each word.
Try it yourself
words = input("Words: ").split()
print(tally_words(words))
Notice
One input line can supply several words to the tally.
For record input, read a row count and then that many name score lines.
Try it yourself
n = int(input("How many records? "))
scores = {}
for i in range(n):
parts = input("Name and score: ").split()
scores[parts[0]] = int(parts[1])
print(scores)
Notice
Each record becomes one dictionary pair; repeated names replace the earlier score in this example.
Put it together: report the vote winner
The opener's raw votes can now become a frequency map. A second loop finds the unique largest count, and an f-string reports the result.
def vote_report(votes):
# Build one integer count for each lowercase choice.
counts = {}
for vote in votes:
choice = vote.lower()
if choice in counts:
counts[choice] = counts[choice] + 1
else:
counts[choice] = 1
winner = ""
winner_count = -1
for choice, count in counts.items():
if count > winner_count:
winner = choice
winner_count = count
return f"{winner} wins with {winner_count} votes"
print(vote_report(["blue", "gold", "blue", "green", "blue", "gold"]))
Output
blue wins with 3 votesVisible payoff: the call returns "blue wins with 3 votes". The function uses meaningful names for each job: raw votes, built counts, current choice, and final winner. Short comments can mark a major stage without repeating every line.
Recap
{'blue': 3}stores a value under the key'blue'.counts[key]reads a known key;counts.get(key, 0)supplies zero for a missing key.key in countschecks keys, and a loop can visit every key or key and value pair.- A counting loop builds a frequency map one vote at a time.
- Another loop can track the key with the largest value.
You can now count the club's votes and report the winning choice.