To start this guide, download this zip file.
Lists of Tuples
Any time you store data in a list you can work with that data using the list patterns we have learned:
- map — create a new list that has the same number of items as the original list, with each item in the original list mapped to an item in the new list
- filter — create a new list that has only some of the items of the original list
- select — choose a single value from the list
- accumulate — add or subtract the values in a list
We will show you a few examples of how to do this with lists of tuples.
Scaling a recipe
Write a program that scales a recipe, for example doubles or triples it. First, the person running the program inputs a list of ingredients. For each ingredient, they should provide the item, the quantity, and the units (for example, cups or tsps). Then the person enters a scaling factor (for example, 2 or 3). The program then prints otu the recipe scaled to that factor, with all quantities rounded to 1 decimal place. For example:
What ingredients are in your recipe?
Ingredient: flour
Quantity: 2
Unit: cups
Ingredient: salt
Quantity: 1
Unit: tsps
Ingredient: baking soda
Quantity: 1
Unit: tsps
Ingredient: water
Quantity: 1
Unit: cups
Ingredient:
Scaling factor: 2.5
New Recipe:
5.0 (cups) flour
2.5 (tsps) salt
2.5 (tsps) baking soda
2.5 (cups) water
Planning
See if you can write this program with a friend. You have starter code in the
zip file above, in the file called recipe.py
:
def main():
# Write code here
pass
if __name__ == '__main__':
main()
Start by decomposing the problem into functions! What are the functions you
would use in main()
?
Here is one way to design the program:
Notice that the black arrows show return values being stored in variables, and blue arrows show those variables being used as arguments in other functions.
We can put this into code:
def main():
recipe = get_ingredients()
factor = get_factor()
recipe = scale_recipe(recipe, factor)
print_recipe(recipe)
Getting ingredients
To get the ingredients, we need to loop forever, getting one ingredient at a
time, until an ingredient is None
:
def get_ingredients():
print('What ingredients are in your recipe?')
recipe = []
while True:
item = get_ingredient()
if item is None:
break
recipe.append(item)
return recipe
This follows the same pattern we saw when doing practice with tuples.
Likewise, to get an individual ingredient we input for each of the pieces of
information we need, and return either None
or a tuple:
def get_ingredient():
ingredient = input('Ingredient: ')
if not ingredient:
return None
quantity = float(input('Quantity: '))
unit = input('Unit: ')
return ingredient, quantity, unit
Getting a factor
To get a factor, we need to ask the person to enter a number. This could be a
floating point number, like 2.5! Remember, input()
can only return a string,
so to convert an integer into a float, we can do this:
def get_factor():
response = input('Scaling factor: ')
factor = float(response)
return factor
Alternatively, we can do this all in one line:
def get_factor():
return float(input('Scaling factor: '))
Scaling the recipe
OK, now comes the part where we need to scale the recipe by the factor. So we need to write this function:
def scale_recipe(recipe, factor):
It takes a recipe, which is a list of ingredients, and a factor, which is a float. Here is an example of what the recipe could have:
recipe = [('flour', 2, 'cups'), ('salt', 1, 'tsps'), ('baking soda', 1, 'tsps'), ('water', 1, 'cups')
To scale the recipe, we need to map each ingredient to a new ingredient that
has, for example, twice as much. The amount we use for the mapping is in the
factor
variable:
new_item = (ingredient, quantity * factor, unit)
Here is the complete function:
def scale_recipe(recipe, factor):
new_recipe = []
for ingredient, quantity, unit in recipe:
new_item = (ingredient, quantity * factor, unit)
new_recipe.append(new_item)
return new_recipe
Printing the recipe
The last step is to print the recipe:
def print_recipe(recipe):
print('New Recipe:')
for ingredient, quantity, unit in recipe:
print(f' {quantity} ({unit}) {ingredient}')
You should be able to run the program and see it working.
Fishing
Write a program that allows a person to input information on a series of fish they have caught. For each catch, the person should provide the place, type, and size (in inches) of the fish. Then allow the person to specify a type of fish to report on. For that type, print a report indicating:
- the total number of fish of that type
- the catch with the largest fish of that type
For example:
Place: Utah Lake
Type of fish: Trout
Size (inches): 6
Place: Lake Powell
Type of fish: Bass
Size (inches): 12
Place: Flaming Gorge
Type of fish: Bass
Size (inches): 18
Place: Strawberry
Type of fish: Trout
Size (inches): 13
Place: Bear Lake
Type of fish: Trout
Size (inches): 15
Place:
Fish type: Trout
Total # of Trout: 3
Best Trout catch: 15.0 inches at Bear lake
Planning
See if you can write this program with a friend. You have starter code in the
zip file above, in the file called fishing.py
:
def main():
# Write code here
pass
if __name__ == '__main__':
main()
Start by decomposing the problem into functions! What are the functions you
would use in main()
?
Here is one way to design the program:
Notice that the black arrows show return values being stored in variables, and blue arrows show those variables being used as arguments in other functions.
Since this is a more complicated program, let’s work one step at a time, and just get the catches first:
def main():
catches = get_catches()
print(catches)
Getting the catches
Getting the catches is just like the previous problems we have worked on:
def get_catches():
catches = []
while True:
catch = get_catch()
if catch is None:
break
catches.append(catch)
return catches
- Start with an empty list of fish
- Loop forever
- Get info on a fish caught
- If the catch is
None
, break - Otherwise, append the fish to the list of catches
- Return the list of fish caught
To get info on an individual fish that was caught:
def get_catch():
place = input('Place: ')
if place == '':
return None
fish = input('Type of fish: ')
size = float(input('Size (inches): '))
return place, fish, size
We should be able to run this program and enter a few fish:
Place: Utah Lake
Type of fish: Trout
Size (inches): 6
Place: Lake Powell
Type of fish: Bass
Size (inches): 12
Then you will see the program print out the list of tuples:
[('Utah Lake', 'Trout', 6.0), ('Lake Powell', 'Bass', 12.0)]
Great!
Filtering the fish
The next step in our diagram is to get a fish type and then filter the list of catches with that type. By filter we mean return a new list of fish that has only fish of that type.
First, modify main()
:
def main():
catches = get_catches()
fish_type = get_fish_type()
catches_of_fish = filter_to_type(catches, fish_type)
print(catches_of_fish)
This will let us do the next step and print out the filtered list of fish, to be sure that next step is working.
Now we can write get_fish_type()
:
def get_fish_type():
return input('Fish type: ')
This is probably the easiest function you will write all semester. :-)
We can also write filter_to_type()
:
def filter_to_type(catches, fish_type):
keepers = []
for place, fish, size in catches:
if fish == fish_type:
keepers.append((place, fish, size))
return keepers
We chose to use keepers
as the variable here because it does a good job of
showing what filter does — it “keeps” some of the items in the original list,
but throws the rest away.
We loop through all the catches, unpacking them as we go. Then only if
fish == fish_type
do we append the fish to the keepers
.
If you run this, and enter the following:
Place: Utah Lake
Type of fish: Trout
Size (inches): 6
Place: Lake Powell
Type of fish: Bass
Size (inches): 12
Place:
Fish type: Trout
Then the program should print:
[('Utah Lake', 'Trout', 6.0)]
Notice how the filter works by creating a new list that keeps only the tuples we want.
Printing a report
Modify main()
one more time:
def main():
catches = get_catches()
fish_type = get_fish_type()
catches_of_fish = filter_to_type(catches, fish_type)
print_report(catches_of_fish, fish_type)
Now we have a complete program. We just need to write print_report()
:
def print_report(catches, fish_type):
place, fish, size = find_max(catches)
print(f'Total # of {fish_type}: {len(catches)}')
print(f'Best {fish} catch: {size} inches at {place}')
We want to have a function called find_max()
that returns a tuple with all the
information about the largest fish caught. This is an example of a select
function. We want to select one of the tuples out of the list of tuples.
def find_max(catches):
best_fish = None
best_place = None
best_size = None
for place, fish, size in catches:
if best_size is None or size > best_size:
best_size = size
best_fish = fish
best_place = place
return best_place, best_fish, best_size
- Start by creating three variables, one for each part of the tuple.
- Initialize each of these variables to
None
to represent the fact that the largest fish hasn’t been found yet. - Loop through all of the fish, using unpacking
- if the best size is
None
or the current size is bigger than the best size, then change all of the three variables to match this fish
- if the best size is
- Return a tuple with information about the biggest fish
Now you can run the program one more time and it should print out the report we need!