Dictionaries are a versatile data structure that can be used in many different ways. In this lesson, we will explore some common patterns for using dictionaries, including using dictionaries as a simple if-else chain, counting with dictionaries, and grouping with dictionaries.
grades = {
"A" : 4.0,
"B" : 3.0,
"C" : 2.0,
"D" : 1.0,
"F" : 0.0
}
def grade_to_gpa(grade: str) -> float:
if grade in grades:
return grades[grade]
else:
return 0.0
print(grade_to_gpa("A")) # Output: 4.0
Dictionaries can be used as a simple if-else chain, where the keys are the conditions and the values are the results. This is useful when you have a fixed set of conditions and results, and you want to look up the result based on the condition.
In a sense, dictionaries are like a function that maps keys to values. Although a function can do more than just look up values, it is often easier for a programmer to write, maintain, and understand a dictionary than a function. Adding new conditions to an if-else chain requires a lot more code than adding a new key-value pair to a dictionary.
# General pattern
counts = {}
for item in values:
if item in counts:
counts[item] += 1
else:
counts[item] = 1
Counting is a common pattern in programming, and dictionaries are a great tool for counting. Previously, we saw how the Count loop pattern would allow us to count the number of times a value appears in a list. This pattern can be generalized to count the number of times any item appears in any collection. The result is a dictionary where the keys are the items and the values are the counts.
The general pattern is to create an empty dictionary, then iterate over the items you want to count. For each item, check if it is already in the dictionary. If it is, increment the count. If it is not, add it to the dictionary with a count of 1.
# Count the number of times each letter appears in a string
def count_letters(text: str) -> dict[str, int]:
counts = {}
for letter in text:
if letter in counts:
counts[letter] += 1
else:
counts[letter] = 1
return counts
print(count_letters("hello"))
# Output: {'h': 1, 'e': 1, 'l': 2, 'o': 1}
print(count_letters("aaabb"))
# Output: {'a': 3, 'b': 2}
The example shown here counts the number of times each letter appears in a string. The function count_letters takes a string s as input and returns a dictionary where the keys are the letters in the string and the values are the counts of each letter. Remember, we can iterate through a string just like a list, getting each character one at a time. This pattern would work regardless of whether the input is a list, a string, or any other collection (like a dictionary!).
# General pattern
groups = {}
for item in values:
key = group_key(item)
if key in groups:
groups[key].append(item)
else:
groups[key] = [item]
Grouping is another common pattern in programming, and dictionaries are once again a great tool for this task. Grouping is the process of taking a collection of items and organizing them into groups based on some key. The result is a dictionary where the keys are the group keys and the values are lists of items that belong to that group.
The example shown here should be familiar to you, since it is actually similar to the Map pattern. However, instead of appending to the same list each time, we create a new list for each key. When we check if the key is in the dictionary, we append to the existing list if it is, or create a new list if it is not.
# Group words by their first letter
def group_words(words: list[str]) -> dict[str, list[str]]:
groups = {}
for word in words:
key = word[0]
if key in groups:
groups[key].append(word)
else:
groups[key] = [word]
return groups
print(group_words(["apple", "banana", "cherry", "avocado", "blueberry"]))
# Output: {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'],
# 'c': ['cherry']}
The example shown here groups words by their first letter. The function group_words takes a list of words as input and returns a dictionary where the keys are the first letters of the words and the values are lists of words that start with that letter. This pattern can be used to group items by any key, not just the first letter.
from dataclasses import dataclass
@dataclass
class Person:
name: str
role: str
people = [
Person("Alice", "Senior Developer"),
Person("Bob", "Developer"),
Person("Carol", "Developer"),
Person("Darrel", "Senior Developer"),
Person("Eve", "Manager")
]
def group_by_role(people: list[Person]) -> dict[str, list[Person]]:
groups = {}
for person in people:
key = person.role
if key in groups:
groups[key].append(person)
else:
groups[key] = [person]
return groups
roles = group_by_role(people)
print(roles["Senior Developer"])
# Output: [Person(name='Alice', role='Senior Developer'),
# Person(name='Darrel', role='Senior Developer')]
The example shown here groups people by their role. The function group_by_role takes a list of Person objects as input and returns a dict where the keys are the roles of the people and the values are lists of People that have that role. Notice that the resulting structure is a dictionary of lists, where each list contains objects of the same type.
The first key in the dictionary is "Senior Developer", which has two people associated with it: Alice and Darrel. The second key is "Developer", which has two people associated with it: Bob and Carol. The third key is "Manager", which has one person associated with it: Eve.
We can easily and quickly access the people in a specific role, as demonstrated by the print statement where we access the people with the role "Senior Developer".