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.
-
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)Scroll the code for more ↓
Output
{'blue': 3, 'gold': 2, 'green': 1}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"])Scroll the code for more ↓
Output
3The 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())Scroll the code for more ↓
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 dtests whetherkeyis one of dictionaryd'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)Scroll the code for more ↓
Output
True False FalseThe calls print
True,False, thenFalse. The value2is stored inmedal_counts, but2 in medal_countsis 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
getd.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"))Scroll the code for more ↓
Output
4 0The calls return
4and0. Use square brackets when a key must exist. Usegetwhen a sensible default handles a missing key.Add or update a pair
Assignment through a key stores a value.
d[key] = valueadds 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))Scroll the code for more ↓
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)Scroll the code for more ↓
Output
{'blue': 4}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 inlevellooks 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))Scroll the code for more ↓
Output
1 10 20A real program can read one Roman symbol and use the lookup table from this lesson.
Try it symbol = input("Roman symbol (I, V, or X): ") print(roman_value(symbol))Scroll the code for more ↓
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 dvisits each key. Used[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}))Scroll the code for more ↓
Output
25The call returns
25. On each loop trip,playerholds one key andscores[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)Scroll the code for more ↓
Output
zinc iron neonThe 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})Scroll the code for more ↓
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})Scroll the code for more ↓
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}))Scroll the code for more ↓
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}))Scroll the code for more ↓
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 scorelines, then total the scores.Try it 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))Scroll the code for more ↓
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/elsepattern 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"]))Scroll the code for more ↓
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)Scroll the code for more ↓
Output
{'m': 1, 'e': 1, 'l': 1, 'o': 1, 'n': 1}melonhas five different letters, so each stored count is1.The
getshortcutAfter you understand the explicit missing-key pattern,
getcan 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"]))Scroll the code for more ↓
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})Scroll the code for more ↓
Output
TrueThe 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"]))Scroll the code for more ↓
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]ingroups[letter]for a new letter, then append togroups[letter]when that letter appears again. Wrong: appending to a fresh list returned bygroups.get(letter, [])when the letter is missing changes that separate list but never stores the new key ingroups.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}))Scroll the code for more ↓
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 withappend.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))Scroll the code for more ↓
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)Scroll the code for more ↓
Output
{'Rin': 12}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 words = input("Words: ").split() print(tally_words(words))Scroll the code for more ↓
One input line can supply several words to the tally.
For record input, read a row count and then that many
name scorelines.Try it 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)Scroll the code for more ↓
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"]))Scroll the code for more ↓
Output
blue wins with 3 votesVisible payoff: the call returns
"blue wins with 3 votes". The function uses meaningful names for each job: rawvotes, builtcounts, currentchoice, and finalwinner. Short comments can mark a major stage without repeating every line.-
{'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.
-