7DICTIONARIES AND STRUCTURING DATA

Like lists, dictionaries let your programs arrange data in complicated structures that are useful for storage and retrieval. If you understand dictionaries, your programs can become more than just a simple collection of loops and if-else code.

A simple drawing of a light bulb. LEARNING OBJECTIVES

  • Master the dictionary data type and how it uses key-value pairs to associate one piece of data with another.
  • Understand the differences between the list and dictionary data types.
  • Be able to apply dictionary methods to access and change the data a dictionary stores.
  • Know how to use dictionaries and lists to model real-world objects and processes.

A grey circle with a white question mark at the center Practice Questions

The following questions review working with dictionaries, their methods, and using them as data structures.

The Dictionary Data Type

Like a list, a dictionary is a mutable collection of many values. But unlike indexes for lists, indexes for dictionaries can use many different data types, not just integers. These dictionary indexes are called keys, and a key with its associated value is called a key-value pair. Answer the following questions about dictionaries and key-value pairs.

  1. 1. In the dictionary {'name': 'Alice', 42: 'answer'}, which parts are the keys of the key-value pairs?

  2. 2. In that same dictionary, which parts are the values?

  3. 3. What error appears when you enter ['name': 'Alice'] into the interactive shell?

  4. 4. How can you fix the code ['name': 'Alice'] to make it a dictionary?

  5. 5. What error appears when you enter {cat: Zophie} into the interactive shell?

  6. 6. How can you fix the code {cat: Zophie} to make it a dictionary?

  7. 7. Is {True: True} a valid dictionary?

Run the code in questions 8 through 10 in the interactive shell to determine whether the two dictionaries shown are the same.

  1. 8. 'name': 'Alice', 'color': 'red'} == {'color': 'red', 'name': 'Alice'}

  2. 9. {'name': 'Alice'} == {'Alice': 'name'}

  3. 10. {'password': '12345'} == {'password': 12345}

  4. 11. Can dictionaries have string keys, such as spam['cat']?

  5. 12. Can they have integer keys, such as spam[3]?

  6. 13. What about negative integer keys, such as spam[-5]?

  7. 14. What error does accessing a nonexistent key in a dictionary cause?

  8. 15. Can a dictionary contain two key-value pairs with identical keys?

  9. 16. Can a dictionary contain two key-value pairs with identical values?

  10. 17. Why is there no “first” or “last” key-value pair in a dictionary?

For questions 18 through 20, assume that spam contains {'name': 'Alice', 'color': 'red'}.

  1. 18. What does list(spam.keys()) evaluate to?

  2. 19. What does list(spam.values()) evaluate to?

  3. 20. What about list(spam.items())?

  4. 21. If spam contains {'42': 'Answer'}, what does spam[42] evaluate to?

  5. 22. If spam contains {0: 'cat', 2: 'dog'}, what does spam[1] evaluate to?

  6. 23. If spam contains {'name': 'Alice'}, does spam.get('color') result in a KeyError?

  7. 24. If spam contains {'name': 'Alice'}, what does spam.get('color', 'red') evaluate to?

  8. 25. If spam contains a dictionary, will the code spam.setdefault('name', 'Alice') ever result in a KeyError?

Model Real-World Things Using Data Structures

Python can use data structures to model actual data; for example, you could create a data structure to represent a chessboard, then write code that interacts with this model to simulate a chess game. Test your ability to use lists and dictionaries to represent real-world objects and processes.

  1. 26. Create a dictionary that captures the following weather information:

    At 3 pm, the temperature was 23.2 degrees Celsius but felt like 24 degrees. The humidity was 91 percent, and pressure was 1,014 hPa (Hectopascal pressure units).

    Store the hourly time as an integer between 0 (representing midnight) and 23 (representing 11 pm). Store temperatures as floating-point numbers (and never as integers). Humidity should be an integer between 0 and 100; pressure should also be an integer. Use the keys 'time', 'temp', 'feels_like', 'humidity', and 'pressure'.

  2. 27. Create a dictionary that captures the following restaurant reservations:

    Alice has a reservation for 3 pm, Bob has a reservation for 5 pm, and Carol has a reservation for 7 pm.

    The keys should be integers ranging from 0 (representing midnight) to 23 (representing 11 pm), and the values should be strings of the customer names.

  3. 28. The restaurant in the previous question has only one table. Is it possible to accidentally have two customers with the same reservation time, causing a conflict over who gets the table? If so, write an example dictionary that includes conflicting reservations.

  4. 29. Let’s change the restaurant reservation dictionary so that the keys are the customer names and the values are the reservation times. Now is it possible to accidentally have two customers with the same reservation time? If so, write an example dictionary that includes conflicting reservations.

Nested Dictionaries and Lists

As you model more complicated things, you may find you need to use dictionaries and lists that contain other dictionaries and lists. Lists are useful for holding an ordered series of values, and dictionaries are useful for associating keys with values. Answer the following questions about nested dictionaries and lists.

  1. 30. A school has the students Alice, Bob, and Carol, who are all in the seventh grade. Another student, David, is in the sixth grade. Write a list of dictionaries that can model this information. The dictionaries should have keys 'name' and 'grade'. The value for the 'grade' key should be an integer. The order of the dictionaries in the list doesn’t matter.

  2. 31. Write the code that would evaluate to the 'Zophie' string in spam if spam contained [{'name': 'Alice', 'age': 3}, {'name': 'Zophie', 'age': 17}].

  3. 32. Write the code that would evaluate to the 3 integer in spam if spam contained [{'name': 'Alice', 'age': 3}, {'name': 'Zophie', 'age': 17}].

  4. 33. Write the code that would evaluate to the 'Zophie' string in spam if spam contained {'humans': ['Alice', 'Bob'], 'pets': ['Zophie', 'Pookah']}.

  5. 34. Say that the first line in a small program is pet_owners = {'Alice': ['Spot', 'Mittens'], 'Al': ['Zophie']}. Write a for loop that prints all of Alice’s pets’ names.

  6. 35. Two teams, 'Home' and 'Visitor', played a game of baseball across nine innings, numbered 1 through 9. (Programmers did not invent baseball, so the first inning is not zero.) To model this game, create a dictionary with the keys 'Home' and 'Visitor'. The values for these two keys should also be dictionaries, with integer keys 1 through 9, to represent each inning. The values for each of the inning keys should be the score for the inning. The score was 0 in all innings except for the third, when the Home team scored one run. (It wasn’t an exciting game.) Write the code for this dictionary.

  7. 36. Instead of manually writing the dictionary in the previous question, write a for loop that can automatically generate it. You can work from the following template:

    game = {'Home': {}, 'Visitor': {}}
    for inning in range(1, 10):  # Loop from 1 to 9.
        # Fill in the code for this part.
    game['Home'][3] = 1  # Set one run in third inning.
  8. 37. A deranged billionaire has purchased the entire baseball league so that they can make the following rule change: All baseball games will now have 9,999 innings instead of 9 innings. Change the code in your previous answer to reflect this new game. Again, the only run scored was by the Home team in the third inning. (The teams were too tired to score any more runs later in the game.)

A simple drawing of a sharpened pencil. Practice Projects

The following practice projects will reinforce what you’ve learned about dictionaries and structuring data.

Random Weather Data Generator

Write a function named get_random_weather_data() that returns a dictionary of random weather data. The dictionary should have the keys and values in Table 7-1.

Table 7-1: Keys and Values for the Weather Dictionary

Key

Value

'temp'

A random float from -50 to 50

'feels_like'

A float that is within 10 degrees of the 'temp' value

'humidity'

A random integer between 0 and 100

'pressure'

A random integer between 990 and 1010

The program should then call this function from a loop 100 times, storing the returned dictionaries in a list. Finally, it should print the list. Save this program in a file named weatherDataGen.py.

Average-Temperature Analyzer

Add a function named get_average_temperature(weather_data) to the program in the previous practice project. This function should accept a list of the weather data dictionaries described in the previous project and return the average temperature in their 'temp' keys. To calculate the average, add all of the temperature numbers in the dictionaries and divide the result by the number of dictionaries.

The list passed to get_average_temperature() can contain any number of dictionaries but should always contain at least one. Generate a list of 100 weather dictionaries by calling get_random_weather_data(), then pass this list to get_average_temperature() and print the average it returns.

Add this new function to your weatherDataGen.py program and save this new program as avgTemp.py.

Chess Rook Capture Predictor

In Chapter 7 of Automate the Boring Stuff with Python, we model a chessboard as a dictionary by using keys of strings for each square. For example, the string 'a1' represents the lower-left corner square, and 'h8' represents the upper-right corner square.

The values in the dictionary are two-character strings representing chess pieces. The first character is a lowercase w for white or b for black, while the second character is an uppercase P, N, B, R, K, or Q for pawn, knight, bishop, rook, king, or queen, respectively. For example, 'wQ' represents a white queen and 'bB' represents a black bishop.

So, the following dictionary represents a chessboard with a white queen in the upper-left square and a black bishop in the square below it: {'a8': 'wQ', 'a7': 'bB'}. If a square doesn’t have a key in the dictionary, we assume the square is unoccupied.

In chess, a rook can move an unlimited number of squares vertically or horizontally across the board. If any of the opponent’s pieces are on the same row (known as the rank in chess) or column (known as the file), the rook can capture it.

Write a function named white_rook_can_capture(rook, board) that takes two arguments: rook is a string representing a square on which a white rook is located, and board is a chessboard dictionary. The function returns a list of all squares with black pieces that the rook can capture—that is, a list of all squares with black pieces (including the black king) in the same row or column as the white rook. The order of the squares in the list doesn’t matter. If the white rook cannot capture any black pieces, the function returns an empty list.

For simplicity, we’ll ignore situations in which another piece blocks the white rook from capturing any pieces. Your function just finds all the black pieces with the same rank or file as the white rook. The returned list should not contain any squares with white pieces.

For example, the function call white_rook_can_capture('d3', {'d7': 'bQ', 'd2': 'wB', 'f1': 'bP', 'a3': 'bN'}) should return the list ['d7', 'a3'] because squares d7 and a3 contain black pieces that a white rook at d3 can capture. The square d7 is in the same column as d3 and the square a3 is in the same row as d3. However, f1 is not in the same column or row as d3. And while d2 is in the same column as d3, it contains a white piece.

Save this program in a file named rookCapture.py.