Exercises: Dictionaries and Sets

These exercises progress from basic dictionary operations through set mathematics to real-world data modeling. All code should run under Python 3.12+.

Difficulty Guide: - ⭐ Foundational (5-10 min each) - ⭐⭐ Intermediate (10-20 min each) - ⭐⭐⭐ Challenging (20-40 min each) - ⭐⭐⭐⭐ Advanced/Research (40+ min each)


Part A: Dictionary Basics ⭐

A.1. Create a dictionary called capitals that maps at least five countries to their capital cities. Then: - Print the capital of one country using bracket notation - Print the capital of a country that isn't in your dict using .get() with a default of "Unknown" - Add a new country-capital pair - Print the total number of countries in your dictionary

A.2. Given the following dictionary:

fruit_prices = {"apple": 1.20, "banana": 0.50, "cherry": 3.00, "date": 5.50}

Write code that: - Prints the price of bananas - Updates the price of cherries to 2.75 - Removes dates from the dictionary using pop() and prints the removed price - Adds "elderberry" with a price of 4.25

A.3. What does each of the following expressions evaluate to? Predict first, then verify in the REPL.

info = {"name": "Alice", "age": 30, "city": "Portland"}
a = "name" in info
b = "Alice" in info
c = 30 in info
d = info.get("phone", "N/A")
e = len(info)

A.4. Explain the difference between del dict[key], dict.pop(key), and dict.pop(key, default). When would you use each one?

A.5. Fix the bugs in this code (there are three):

student = {"Name": "Bob", "grade" = "A", "gpa": 3.8}
print(student["name"])
student[[1, 2]] = "courses"

Part B: Iteration and Patterns ⭐⭐

B.1. Given a dictionary of students and their test scores:

scores = {
    "Alice": [88, 92, 85, 91],
    "Bob": [75, 80, 72, 68],
    "Carol": [95, 98, 92, 97],
    "Dave": [60, 55, 70, 65],
}

Write code that: - Calculates and prints each student's average score - Identifies the student with the highest average - Prints the names of students whose average is below 70

B.2. Write a function invert_dict(d) that takes a dictionary and returns a new dictionary with keys and values swapped. If two keys in the original have the same value, raise a ValueError with a helpful message. Test it with:

colors = {"red": "#FF0000", "green": "#00FF00", "blue": "#0000FF"}
grades = {"Alice": "A", "Bob": "B", "Carol": "A"}  # Should raise ValueError

B.3. Write a function merge_inventories(inv1, inv2) that takes two inventory dictionaries (item name → quantity) and returns a single dictionary where quantities are summed for items that appear in both:

shop_a = {"sword": 3, "shield": 2, "potion": 10}
shop_b = {"shield": 1, "potion": 5, "bow": 4}
# Expected: {"sword": 3, "shield": 3, "potion": 15, "bow": 4}

B.4. Write a function word_frequency(text) that takes a string, converts it to lowercase, splits it into words, removes basic punctuation (periods, commas, exclamation marks, question marks), and returns a dictionary mapping each word to its frequency. Test it with:

text = "To be, or not to be, that is the question."

Expected: {'to': 2, 'be': 2, 'or': 1, 'not': 1, 'that': 1, 'is': 1, 'the': 1, 'question': 1}

B.5. Dr. Patel has multiple DNA sequences and wants to compare their nucleotide composition. Write a function nucleotide_profile(sequence) that returns a dictionary with the percentage of each nucleotide (A, T, G, C), rounded to one decimal place. Then compare two sequences:

seq1 = "ATGCGATCGATCGATCATGCATGC"
seq2 = "AAATTTGGGCCCAAATTTGGGCCC"

B.6. Write a function most_common_value(d) that takes a dictionary and returns the value that appears most frequently. If there's a tie, return any one of the tied values. Do NOT use Counter — build the frequency count manually.


Part C: Dictionary Comprehensions ⭐⭐

C.1. Using a dictionary comprehension, create a dictionary that maps numbers 1-10 to their cubes. Example: {1: 1, 2: 8, 3: 27, ...}

C.2. Given a dictionary of student scores:

scores = {"Alice": 92, "Bob": 67, "Carol": 88, "Dave": 45, "Eve": 73, "Frank": 91}

Use a dictionary comprehension to create: - A dict of only students who passed (score >= 70) - A dict mapping each student to their letter grade ("A" for 90+, "B" for 80-89, "C" for 70-79, "F" for below 70)

C.3. Given two lists of equal length:

keys = ["name", "age", "city", "language"]
values = ["Priya", 28, "Mumbai", "Python"]

Use zip() and a dictionary comprehension to create a dictionary from these two lists. Then do it again using the dict() constructor with zip() directly (no comprehension needed). Which is more readable?

C.4. Write a dictionary comprehension that takes a string and produces a dictionary of {character: ascii_value} for each unique character. Apply it to "Hello". (Hint: ord() gives the ASCII value of a character.)


Part D: Sets ⭐⭐

D.1. Given the following lists, use sets to answer each question:

cs_students = ["Alice", "Bob", "Carol", "Dave", "Eve"]
math_students = ["Bob", "Dave", "Frank", "Grace"]
physics_students = ["Carol", "Eve", "Frank", "Hank"]
  • Who is enrolled in both CS and Math?
  • Who is enrolled in CS but not Physics?
  • Who is enrolled in all three courses?
  • How many unique students are there across all three courses?

D.2. Write a function find_duplicates(items) that takes a list and returns a set of elements that appear more than once. Do NOT use Counter — use set logic.

find_duplicates([1, 2, 3, 2, 4, 3, 5])  # {2, 3}
find_duplicates(["a", "b", "c"])          # set()

D.3. A spell-checker compares words in a document against a dictionary of valid words. Write a function check_spelling(text, valid_words) where text is a string and valid_words is a set. Return a set of misspelled words (words in the text but not in the valid dictionary). Ignore case.

valid = {"the", "cat", "sat", "on", "mat", "a", "is", "and"}
text = "The cat sat on a rug and the dog barked"
# Expected: {"rug", "dog", "barked"}

D.4. Two friends compare their music libraries:

alice_songs = {"Bohemian Rhapsody", "Stairway to Heaven", "Hotel California",
               "Imagine", "Smells Like Teen Spirit"}
bob_songs = {"Hotel California", "Imagine", "Yesterday",
             "Like a Rolling Stone", "Bohemian Rhapsody"}

Write code to find: - Songs they can share with each other (songs only one of them has) - Songs they both already have - All unique songs between them


Part E: Integrated Challenges ⭐⭐⭐

E.1. Inventory Manager. Build a simple inventory system for the "Crypts of Pythonia" text adventure. Write functions: - add_item(inventory, item, quantity=1) — add items (stack if already present) - remove_item(inventory, item, quantity=1) — remove items (don't go below 0) - has_item(inventory, item, min_quantity=1) — check if player has enough - display_inventory(inventory) — formatted display

Test scenario:

inv = {}
add_item(inv, "torch", 3)
add_item(inv, "sword")
add_item(inv, "torch", 2)  # Now has 5 torches
remove_item(inv, "torch", 2)  # Now has 3 torches
print(has_item(inv, "torch", 5))  # False (only 3)
display_inventory(inv)

E.2. Grade Book. Create a grade book system using nested dictionaries:

gradebook = {
    "Alice": {"homework": [90, 85, 92], "exams": [88, 92], "participation": 95},
    "Bob": {"homework": [78, 80, 72], "exams": [75, 68], "participation": 85},
}

Write functions: - calculate_final(student_record, hw_weight=0.4, exam_weight=0.5, part_weight=0.1) — weighted final grade - class_average(gradebook) — overall class average - top_student(gradebook) — name of highest-scoring student

E.3. Log Analyzer. Given a list of server log entries (as strings), build a function that returns a report dictionary:

logs = [
    "2024-01-15 10:23:01 ERROR Database connection failed",
    "2024-01-15 10:23:05 INFO Retrying connection",
    "2024-01-15 10:23:06 INFO Connection established",
    "2024-01-15 10:24:00 WARNING Disk usage at 85%",
    "2024-01-15 10:25:30 ERROR Authentication failed",
    "2024-01-15 10:25:31 INFO User logged out",
    "2024-01-15 10:26:00 ERROR Database connection failed",
]

Your function should return:

{
    "total_entries": 7,
    "by_level": {"ERROR": 3, "INFO": 3, "WARNING": 1},
    "unique_errors": {"Database connection failed", "Authentication failed"},
    "error_rate": 42.9,  # percentage, rounded to 1 decimal
}

E.4. Election Results. Process election data:

votes = ["Alice", "Bob", "Alice", "Carol", "Bob", "Alice",
         "Carol", "Carol", "Bob", "Alice", "Carol", "Carol"]

Write a function election_results(votes) that returns a dictionary with: - "counts": vote counts per candidate - "winner": name of the winner - "margin": difference between first and second place - "total_votes": total number of votes cast


Part F: Advanced Challenges ⭐⭐⭐⭐

F.1. Two-Sum Problem. Given a list of integers and a target sum, find all pairs of numbers that add up to the target. Use a set for O(n) performance instead of the O(n²) brute-force approach with nested loops.

def two_sum(numbers, target):
    """Return a list of (a, b) tuples where a + b == target.
    Each number can only be used once. a < b in each pair."""
    pass  # Your code here

print(two_sum([2, 7, 11, 15, 1, 8], 9))
# [(1, 8), (2, 7)]

F.2. Sparse Matrix. A sparse matrix has mostly zero values. Instead of storing all those zeros in a 2D list, use a dictionary with tuple keys (row, col) to store only non-zero values: - set_value(matrix, row, col, value) — set a value (delete if zero) - get_value(matrix, row, col) — get a value (default 0) - add_matrices(m1, m2) — add two sparse matrices - display_matrix(matrix, rows, cols) — pretty-print the full grid

F.3. Social Network Analysis. Model a social network as a dictionary where each person maps to a set of their friends:

network = {
    "Alice": {"Bob", "Carol"},
    "Bob": {"Alice", "Dave"},
    "Carol": {"Alice", "Dave", "Eve"},
    "Dave": {"Bob", "Carol"},
    "Eve": {"Carol"},
}

Write functions: - mutual_friends(network, person1, person2) — who are friends with both? - friend_suggestions(network, person) — friends of friends who aren't already friends (and aren't the person themselves) - most_connected(network) — person with the most friends