NESTING

Credit: The information below has been obtained from http://introtopython.org and used with permission under the MIT license. 

Nesting is one of the most powerful concepts we have come to so far. Nesting involves putting a list or dictionary inside another list or dictionary. We will look at two examples here, lists inside of a dictionary and dictionaries inside of a dictionary. With nesting, the kind of information we can model in our programs is expanded greatly.

LISTS IN A DICTIONARY

A dictionary connects two pieces of information. Those two pieces of information can be any kind of data structure in Python. Let’s keep using strings for our keys, but let’s try giving a list as a value.

The first example will involve storing a number of people’s favorite numbers. The keys consist of people’s names, and the values are lists of each person’s favorite numbers. In this first example, we will access each person’s list one at a time.

[python]
# This program stores people’s favorite numbers, and displays them.
favorite_numbers = {‘eric’: [3, 11, 19, 23, 42],
‘ever’: [2, 4, 5],
‘willie’: [5, 35, 120],
}

# Display each person’s favorite numbers.
print("Eric’s favorite numbers are:")
print(favorite_numbers[‘eric’])

print("\nEver’s favorite numbers are:")
print(favorite_numbers[‘ever’])

print("\nWillie’s favorite numbers are:")
print(favorite_numbers[‘willie’])
[/python]

We are really just working our way through each key in the dictionary, so let’s use a for loop to go through the keys in the dictionary:

[python highlight=”7-10″]
# This program stores people’s favorite numbers, and displays them.
favorite_numbers = {‘eric’: [3, 11, 19, 23, 42],
‘ever’: [2, 4, 5],
‘willie’: [5, 35, 120],
}

# Display each person’s favorite numbers.
for name in favorite_numbers:
print("\n%s’s favorite numbers are:" % name.title())
print(favorite_numbers[name])
[/python]

This structure is fairly complex, so don’t worry if it takes a while for things to sink in. The dictionary itself probably makes sense; each person is connected to a list of their favorite numbers.

This works, but we’d rather not print raw Python in our output. Let’s use a for loop to print the favorite numbers individually, rather than in a Python list.

[python highlight=”10-13″]
# This program stores people’s favorite numbers, and displays them.
favorite_numbers = {‘eric’: [3, 11, 19, 23, 42],
‘ever’: [2, 4, 5],
‘willie’: [5, 35, 120],
}

# Display each person’s favorite numbers.
for name in favorite_numbers:
print("\n%s’s favorite numbers are:" % name.title())
# Each value is itself a list, so we need another for loop
# to work with the list.
for favorite_number in favorite_numbers[name]:
print(favorite_number)
[/python]

Things get a little more complicated inside the for loop. The value is a list of favorite numbers, so the for loop pulls each favorite_number out of the list one at a time. If it makes more sense to you, you are free to store the list in a new variable, and use that to define your for loop:

[python highlight=”11-14″]
# This program stores people’s favorite numbers, and displays them.
favorite_numbers = {‘eric’: [3, 11, 19, 23, 42],
‘ever’: [2, 4, 5],
‘willie’: [5, 35, 120],
}

# Display each person’s favorite numbers.
for name in favorite_numbers:
print("\n%s’s favorite numbers are:" % name.title())

# Each value is itself a list, so let’s put that list in a variable.
current_favorite_numbers = favorite_numbers[name]
for favorite_number in current_favorite_numbers:
print(favorite_number)
[/python]

DICTIONARIES IN A DICTIONARY

The most powerful nesting concept we will cover right now is nesting a dictionary inside of a dictionary. Note that this topic will be more advanced.

To demonstrate this, let’s make a dictionary of pets, with some information about each pet. The keys for this dictionary will consist of the pet’s name. The values will include information such as the kind of animal, the owner, and whether the pet has been vaccinated.

[python]
# This program stores information about pets. For each pet,
# we store the kind of animal, the owner’s name, and
# the breed.
pets = {‘willie’: {‘kind’: ‘dog’, ‘owner’: ‘eric’, ‘vaccinated’: True},
‘walter’: {‘kind’: ‘cockroach’, ‘owner’: ‘eric’, ‘vaccinated’: False},
‘peso’: {‘kind’: ‘dog’, ‘owner’: ‘chloe’, ‘vaccinated’: True},
}

# Let’s show all the information for each pet.
print("Here is what I know about Willie:")
print("kind: " + pets[‘willie’][‘kind’])
print("owner: " + pets[‘willie’][‘owner’])
print("vaccinated: " + str(pets[‘willie’][‘vaccinated’]))

print("\nHere is what I know about Walter:")
print("kind: " + pets[‘walter’][‘kind’])
print("owner: " + pets[‘walter’][‘owner’])
print("vaccinated: " + str(pets[‘walter’][‘vaccinated’]))

print("\nHere is what I know about Peso:")
print("kind: " + pets[‘peso’][‘kind’])
print("owner: " + pets[‘peso’][‘owner’])
print("vaccinated: " + str(pets[‘peso’][‘vaccinated’]))

[/python]

Clearly this is some repetitive code, but it shows exactly how we access information in a nested dictionary. In the first set of print statements, we use the name ‘willie’ to unlock the ‘kind’ of animal he is, the ‘owner’ he has, and whether or not he is ‘vaccinated’. We have to wrap the vaccination value in the str function so that Python knows we want the words ‘True’ and ‘False’, not the values True and False. We then do the same thing for each animal.

Let’s rewrite this program, using a for loop to go through the dictionary’s keys:

[python highlight=”9-14″]
# This program stores information about pets. For each pet,
# we store the kind of animal, the owner’s name, and
# the breed.
pets = {‘willie’: {‘kind’: ‘dog’, ‘owner’: ‘eric’, ‘vaccinated’: True},
‘walter’: {‘kind’: ‘cockroach’, ‘owner’: ‘eric’, ‘vaccinated’: False},
‘peso’: {‘kind’: ‘dog’, ‘owner’: ‘chloe’, ‘vaccinated’: True},
}

# Let’s show all the information for each pet.
for pet_name, pet_information in pets.items():
print("\nHere is what I know about %s:" % pet_name.title())
print("kind: " + pet_information[‘kind’])
print("owner: " + pet_information[‘owner’])
print("vaccinated: " + str(pet_information[‘vaccinated’]))
[/python]

This code is much shorter and easier to maintain. But even this code will not keep up with our dictionary. If we add more information to the dictionary later, we will have to update our print statements. Let’s put a second for loop inside the first loop in order to run through all the information about each pet:

[python highlight=”13-14″]
# This program stores information about pets. For each pet,
# we store the kind of animal, the owner’s name, and
# the breed.
pets = {‘willie’: {‘kind’: ‘dog’, ‘owner’: ‘eric’, ‘vaccinated’: True},
‘walter’: {‘kind’: ‘cockroach’, ‘owner’: ‘eric’, ‘vaccinated’: False},
‘peso’: {‘kind’: ‘dog’, ‘owner’: ‘chloe’, ‘vaccinated’: True},
}

# Let’s show all the information for each pet.
for pet_name, pet_information in pets.items():
print("\nHere is what I know about %s:" % pet_name.title())
# Each animal’s dictionary is in ‘information’
for key in pet_information:
print(key + ": " + str(pet_information[key]))
[/python]

This nested loop can look pretty complicated, so again, don’t worry if it doesn’t make sense for a while.

    1. The first loop gives us all the keys in the main dictionary, which consist of the name of each pet.
    2. Each of these names can be used to ‘unlock’ the dictionary of each pet.
    3. The inner loop goes through the dictionary for that individual pet, and pulls out all of the keys in that individual pet’s dictionary.
    4. We print the key, which tells us the kind of information we are about to see, and the value for that key.
    5. You can see that we could improve the formatting in the output.
    6. We could capitalize the owner’s name.
    7. We could print ‘yes’ or ‘no’, instead of True and False.

Let’s show one last version that uses some if statements to clean up our data for printing:

[python highlight=”14-26″]
# This program stores information about pets. For each pet,
# we store the kind of animal, the owner’s name, and
# the breed.
pets = {‘willie’: {‘kind’: ‘dog’, ‘owner’: ‘eric’, ‘vaccinated’: True},
‘walter’: {‘kind’: ‘cockroach’, ‘owner’: ‘eric’, ‘vaccinated’: False},
‘peso’: {‘kind’: ‘dog’, ‘owner’: ‘chloe’, ‘vaccinated’: True},
}

# Let’s show all the information for each pet.
for pet_name, pet_information in pets.items():
print("\nHere is what I know about %s:" % pet_name.title())
# Each animal’s dictionary is in pet_information
for key in pet_information:
if key == ‘owner’:
# Capitalize the owner’s name.
print(key + ": " + pet_information[key].title())
elif key == ‘vaccinated’:
# Print ‘yes’ for True, and ‘no’ for False.
vaccinated = pet_information[‘vaccinated’]
if vaccinated:
print (‘vaccinated: yes’)
else:
print (‘vaccinated: no’)
else:
# No special formatting needed for this key.
print(key + ": " + pet_information[key])
[/python]

This code is a lot longer, and now we have nested if statements as well as nested for loops. But keep in mind, this structure would work if there were 1000 pets in our dictionary, and it would work if we were storing 1000 pieces of information about each pet. One level of nesting lets us model an incredible array of information.

AN IMPORTANT NOT ABOUT NESTING

While one level of nesting is really useful, nesting much deeper than that gets really complicated, really quickly. There are other structures such as classes which can be even more useful for modeling information. In addition to this, we can use Python to store information in a database, which is the proper tool for storing deeply nested information.

Often times when you are storing information in a database you will pull a small set of that information out and put it into a dictionary, or a slightly nested structure, and then work with it. But you will rarely, if ever, work with Python data structures nested more than one level deep.

EXERCISES

Mountain Heights 3

  • This is an extension of Mountain Heights program completed in the last section. Make sure you save this program under a different filename, such as mountain_heights_3.py, so that you can go back to your original program if you need to.
    • The list of tallest mountains in the world provided all elevations in meters. Convert each of these elevations to feet, given that a meter is approximately 3.28 feet. You can do these calculations by hand at this point.
    • Create a new dictionary, where the keys of the dictionary are still the mountains’ names. This time however, the values of the dictionary should be a list of each mountain’s elevation in meters, and then in feet: {‘everest’: [8848, 29029]}
    • Print out just the mountains’ names, by looping through the keys of your dictionary.
    • Print out just the mountains’ elevations in meters, by looping through the values of your dictionary and pulling out the first number from each list.
    • Print out just the mountains’ elevations in feet, by looping through the values of your dictionary and pulling out the second number from each list.
    • Print out a series of statements telling how tall each mountain is: “Everest is 8848 meters tall, or 29029 feet.”
  • Bonus:
    • Start with your original program from Mountain Heights. Write a function that reads through the elevations in meters, and returns a list of elevations in feet. Use this list to create the nested dictionary described above.

Mountain Heights 4

  • This is one more extension of Mountain Heights.
    • Create a new dictionary, where the keys of the dictionary are once again the mountains’ names. This time, the values of the dictionary are another dictionary. This dictionary should contain the elevation in either meters or feet, and the range that contains the mountain. For example: {‘everest’: {‘elevation’: 8848, ‘range’: ‘himalaya’}}.
    • Print out just the mountains’ names.
    • Print out just the mountains’ elevations.
    • Print out just the range for each mountain.
    • Print out a series of statements that say everything you know about each mountain: “Everest is an 8848-meter tall mountain in the Himalaya range.”