I want to print out an itemized receipt with total cost - python

I am a beginner in programming and I'm working on the projects in Automate the Boring Stuff with Python, In the book there is a project to create a sandwich, then return the total cost. I want to add to my program by providing an itemized receipt. For example, if I put in an order for 1 sandwich with wheat and chicken and 3 sandwiches with white and turkey, the receipt should show something like this (I will format it better when I figure it out):
1 sandwich ---3.5
wheat, chicken
3 sandwich ---10.5.
white, turkey
Total --- 14.00
My challenge is storing the different sandwich orders into different variables and printing them out at the end.
My code below:
menu = {
'wheat': 1.5, 'white': 1, 'sourdough': 2,
'chicken': 2, 'turkey': 2.5, 'ham': 2, 'tofu': 3,
'cheddar': 0.5, 'mozzarella': 0.25, 'american': 0.5,
'mayo': 0.25, 'mustard': 0.25, 'lettuce': 0.5, 'tomato': 0.5
}
total = 0.0
subtotal = 0.0
while True:
order = {}
print('What bread would you like?')
order['bread'] = pyip.inputChoice(['wheat', 'white', 'sourdough'])
print('How about for your protein?')
order['protein'] = pyip.inputChoice(['chicken', 'turkey', 'ham', 'tofu'])
wantCheese = pyip.inputYesNo('Would you like cheese on the sandwich?')
if wantCheese == 'yes':
order['cheese'] = pyip.inputChoice(['cheddar', 'mozzarella', 'american'])
wantToppings = pyip.inputYesNo('Would you like to add extra toppings?')
if wantToppings == 'yes':
while True:
order['side'] = pyip.inputChoice(['mayo', 'mustard', 'lettuce', 'tomato'])
anotherTopping = pyip.inputYesNo('Would you like another topping?')
if anotherTopping == 'no':
break
orderNumber = pyip.inputInt('How many of those sandwiches would you like? ', min = 1)
for choice in order:
if order[choice] in menu.keys():
subtotal += menu[order[choice]]
total *= orderNumber
total += subtotal
subtotal = 0
anotherOrder = pyip.inputYesNo('Would you like to order another sandwich?')
if anotherOrder == 'no':
break
print(total)

Adjust the following as you see fit. FYI, while coding this up I had "let's get this to work" in mind as opposed to "let's make this as efficient as possible". Moreover, you should format the receipt however you like.
Importantly, I created a list called orders just before the while that will be used to store orders. The form of the elements of orders will be 3-tuples where the first element of the 3-tuple records orderNumber, the third element records the subtotal, and the second element is an order dictionary, just as in your original code, except order["side"] will be a list as this allows for multiple additional toppings to be added. For the sample output below, orders is
[(2, {'bread': 'wheat', 'protein': 'chicken', 'cheese': 'cheddar', 'side': ['mustard', 'lettuce']}, 9.5), (1, {'bread': 'sourdough', 'protein': 'turkey', 'side': []}, 4.5)]
As you can see, there are 2 orders of 'wheat', 'chicken', 'cheddar', 'mustard', 'lettuce' (subtotal 9.5) and 1 order of 'sourdough', 'turkey' (subtotal 4.5).
I hope this helps. Any questions please let me know.
import pyinputplus as pyip
menu = {'wheat': 1.5, 'white': 1, 'sourdough': 2,
'chicken': 2, 'turkey': 2.5, 'ham': 2, 'tofu': 3,
'cheddar': 0.5, 'mozzarella': 0.25, 'american': 0.5,
'mayo': 0.25, 'mustard': 0.25, 'lettuce': 0.5, 'tomato': 0.5
}
orders = []
while True:
order = {}
# choose bread
print("What bread would you like?")
order['bread'] = pyip.inputChoice(['wheat', 'white', 'sourdough'])
# choose protein
print("How about for your protein?")
order['protein'] = pyip.inputChoice(['chicken', 'turkey', 'ham', 'tofu'])
# choose cheese
wantCheese = pyip.inputYesNo("Would you like cheese on the sandwich?")
if wantCheese == 'yes':
order['cheese'] = pyip.inputChoice(['cheddar', 'mozzarella', 'american'])
# choose extra toppings
order["side"] = []
wantToppings = pyip.inputYesNo("Would you like to add extra toppings?")
if wantToppings == 'yes':
while True:
order["side"].append(pyip.inputChoice(
['mayo', 'mustard', 'lettuce', 'tomato']))
anotherTopping = pyip.inputYesNo("Would you like another topping?")
if anotherTopping == 'no':
break
# order number
orderNumber = pyip.inputInt(
"How many of those sandwiches would you like?", min = 1)
# subtotal
subtotal = sum(menu[order[key]] for key in order if key != 'side')
subtotal += sum(menu[j] for j in order['side'])
subtotal *= orderNumber
# add 3-tuple to orders list
orders.append((orderNumber, order, subtotal))
# another order?
anotherOrder = pyip.inputYesNo("Would you like to order another sandwich?")
if anotherOrder == 'no':
break
# add subtotals to form total
total = sum(order[2] for order in orders)
# print orders (for programmer use)
print(f"\nOrders: {orders}")
# print receipt
print(f"\nReceipt\n")
for order in orders:
print(f"{order[0]} sandwich ---{order[2]}")
print(" ", end = "")
for key in order[1]:
if isinstance(order[1][key], list):
for x in order[1][key]:
print(x, end = ", ")
else:
print(order[1][key], end = ", ")
print("\n")
print(f"Total --- {total}")
Sample output:
Receipt
2 sandwich ---9.5
wheat, chicken, cheddar, mustard, lettuce,
1 sandwich ---4.5
sourdough, turkey,
Total --- 14.0

Related

Is there a way to get the key from a list embedded in a dictionary

I am trying to write a function that, given a dictionary of restaurants, allows you to randomly pick a restaurant based on your choice of one of the values. For example, if you say you want a bakery then it will only give you bakeries.
I have only worked on the code for choosing the type of restaurant so far, and I am struggling with how to generate a random list. So I am checking for a value and, if it has it, would want to add the key to a list. Does anyone have any suggestions on how to do this?
import random
Restaurants ={
"Eureka": ["American", "$$", "Lunch", "Dinner"],
"Le_Pain": ["Bakery", "$$", "Breakfast", "Lunch", "Dinner"],
"Creme_Bakery": ["Bakery", "$", "Snack"]
}
list=[]
def simple_chooser():
print('Would you like to lock a category or randomize? (randomize, type, price, or meal)')
start= input()
if start=="randomize":
return #completely random
elif start=="type":
print("American, Bakery, Pie, Ice_Cream, Bagels, Asian, Chocolate, Italian, Pizza, Thai, Mexican, Japanese, Acai, Mediterranean, or Boba/Coffee?")
type=input()
for lst in Restaurants.values():
for x in lst:
if x==type:
list.append(x)
return(random.choice(list))
To return completely random restaurant suggestions you need to create a list of all the types first and then you can choose one and return the names of the restaurants.
import random
Restaurants ={
"Eureka": ["American", "$$", "Lunch", "Dinner"],
"Le_Pain": ["Bakery", "$$", "Breakfast", "Lunch", "Dinner"],
"Creme_Bakery": ["Bakery", "$", "Snack"]
}
types = ['American', 'Bakery', 'Pie', 'Ice_Cream', 'Bagels', 'Asian', 'Chocolate', 'Italian',
'Pizza', 'Thai', 'Mexican', 'Japanese', 'Acai', 'Mediterranean','Boba/Coffee']
def simple_chooser():
l=[]
print('Would you like to lock a category or randomize? (randomize, type, price, or meal)')
start= input()
if start=="randomize":
type_random = random.choice(types)
for k,v in Restaurants.items():
if v[0] == type_random:
l.append(k)
elif start=="type":
print("American, Bakery, Pie, Ice_Cream, Bagels, Asian, Chocolate, Italian, Pizza, Thai, Mexican, Japanese, Acai, Mediterranean, or Boba/Coffee?")
type_chosen=input()
for k,v in Restaurants.items():
if v[0] == type_chosen:
l.append(k)
return(random.choice(l))
Also, you don't need to return in if-else statements. Once you have your list of Restaurants you can randomly choose a restaurant and return it.
In your loop, you don't have the restaurant name, as you iterate on the values, you would have need something like
for name, props in Restaurants.items():
if props[0] == type:
list.append(name)
return (random.choice(list)) # wait for the whole list to be constructed
With a better naming (don't use type and list that are builtin methods)
def simple_chooser():
start = input('Would you like to lock a category or randomize? (randomize, type, price, or meal)')
if start == "randomize":
return # completely random
elif start == "type":
restaurant_type = input("American, Bakery, Pie, Ice_Cream, Bagels, Asian, Chocolate, Italian, "
"Pizza, Thai, Mexican, Japanese, Acai, Mediterranean, or Boba/Coffee?")
matching_names = [name for name, props in Restaurants.items() if props[0] == restaurant_type]
return random.choice(matching_names)
You make processing difficult because of the design of your data structures.
Here's an idea which should be easily adapted to future needs.
import random
from operator import contains, eq
Restaurants = [
{'name': 'Eureka', 'type': 'American', 'price': '$$', 'meal': ('Dinner',)},
{'name': 'Le_Pain', 'type': 'Bakery', 'price': '$$', 'meal': ('Lunch', 'Dinner')},
{'name': 'Creme_Bakery', 'type': 'Bakery', 'price': '$', 'meal': ('Snack',)}
]
def get_attr(k):
s = set()
for r in Restaurants:
if isinstance(r[k], tuple):
for t in r[k]:
s.add(t)
else:
s.add(r[k])
return s
def choose_restaurant():
categories = ', '.join(Restaurants[0])
while True:
choice = input(f'Select by category ({categories}) or choose random: ')
if choice == 'random':
return random.choice(Restaurants)
if choice in Restaurants[0]:
choices = get_attr(choice)
if (v := input(f'Select value for {choice} from ({", ".join(choices)}): ')) in choices:
op = contains if isinstance(Restaurants[0][choice], tuple) else eq
return [r for r in Restaurants if op(r[choice], v)]
print('Invalid selection\x07')
print(choose_restaurant())
Restaurants is now a list of dictionaries which is easy to extend. You just need to make sure that each new restaurant has the same structure (keys). Also note that the 'meal' value is a tuple even if there's a single value

Why won't my variables update their values?

I am using python to make a five guys nutrition calculator, and entered all the nutritional info into a dictionary. I have individual variables such as carbs, calories, protein, etc. and update them by adding the values inside them with the values from dictionaries. The dictionary is long, so the first couple keys are
fiveguys_menu = {'burger': {'hamburger':[700, 39, 39, 43, 19.5, 2, 430, 8, 2], 'cheeseburger':[770, 39, 43, 49, 23.5, 2.2, 790, 8, 2],...}
first_food = input("What're you tryna eat? Please state whether you want a burger or fries, fatty.\n").lower().replace(" ", "")
if 'burger' in first_food:
while True:
burger_type = input('Out of hamburger, cheeseburger, baconburger, and bacon cheeseburger, which one do you want?\n').lower().replace(" ", "")
if 'ham' in burger_type:
calories = fiveguys_menu['burger']['hamburger'][0]
carbs = fiveguys_menu['burger']['hamburger'][1]
protein = fiveguys_menu['burger']['hamburger'][2]
total_fat = fiveguys_menu['burger']['hamburger'][3]
sat_fat = fiveguys_menu['burger']['hamburger'][4]
trans_fat = fiveguys_menu['burger']['hamburger'][5]
sodium = fiveguys_menu['burger']['hamburger'][6]
sugar = fiveguys_menu['burger']['hamburger'][7]
fiber = fiveguys_menu['burger']['hamburger'][8]
print_message("One hamburger coming up.")
print(calories, carbs, protein, total_fat, sat_fat, trans_fat, sodium, sugar, fiber)
However, when trying to update the macro variables with the toppings list, the variables will not update.
fiveguys_toppings = {'a1sauce':[15, 3, 0, 0, 0,0, 280, 2, 0], 'barbeque':[60, 15, 0, 0, 0, 0, 400, 10, 0], ...}
while True:
burger_toppings = input("The toppings available are A1 Sauce, barbeque, green pepper, grilled mushrooms, hot sauce, jalapenos, ketchup, lettuce, mayo, mustard, onions, pickles, relish, and tomatoes\nWhat toppings do you want? Please be specific to the spelling listed. \n").lower().replace(" ", "")
if burger_toppings == True:
calories += fiveguys_toppings[burger_toppings][0]
carbs += fiveguys_toppings[burger_toppings][1]
protein += fiveguys_toppings[burger_toppings][2]
total_fat += fiveguys_toppings[burger_toppings][3]
sat_fat += fiveguys_toppings[burger_toppings][4]
trans_fat += fiveguys_toppings[burger_toppings][5]
sodium += fiveguys_toppings[burger_toppings][6]
sugar += fiveguys_toppings[burger_toppings][7]
fiber += fiveguys_toppings[burger_toppings][8]
print(calories, carbs, protein, total_fat, sat_fat, trans_fat, sodium, sugar, fiber)
Why does this while True loop not update the macro variables?
burger_toppings = input(...) - so it will equal whatever was input, not the boolean True. You can change your if statement to be if burger_toppings:, which will evaluate to True if burger_toppings is true-ish (not empty string, not empty list, not None object, etc).
Your code checks for burger_toppings to be True, which it never will be since it's a str. Try:
fiveguys_toppings = {
'a1sauce': [15, 3, 0, 0, 0, 0, 280, 2, 0],
'barbeque': [60, 15, 0, 0, 0, 0, 400, 10, 0], ...}
while True:
burger_toppings = input(
"The toppings available are A1 Sauce, barbeque, green pepper, "
"grilled mushrooms, hot sauce, jalapenos, ketchup, lettuce, mayo, "
"mustard, onions, pickles, relish, and tomatoes.\n"
"What toppings do you want? "
"Please be specific to the spelling listed.\n"
).lower().replace(" ", "")
if burger_toppings not in fiveguys_toppings:
print(f"{burger_toppings.capitalize()} is not one of the options!")
continue
calories += fiveguys_toppings[burger_toppings][0]
carbs += fiveguys_toppings[burger_toppings][1]
protein += fiveguys_toppings[burger_toppings][2]
total_fat += fiveguys_toppings[burger_toppings][3]
sat_fat += fiveguys_toppings[burger_toppings][4]
trans_fat += fiveguys_toppings[burger_toppings][5]
sodium += fiveguys_toppings[burger_toppings][6]
sugar += fiveguys_toppings[burger_toppings][7]
fiber += fiveguys_toppings[burger_toppings][8]
print(calories, carbs, protein, total_fat, sat_fat, trans_fat, sodium, sugar, fiber)

How can I look up data in my code without lots of if/elif/elif/... conditions?

This is a personal project of mine and right now my program is a ton of if-statements based off dictionaries I made holding each seasons episode number (different seasons have different number of episodes) and title. I get the desired results, however I am stuck in trying to find a more advanced method such as using a function, list comprehension or objects to display it more elegantly and with less lines of code.
I've been trying to figure out how to use one of these other methods via googling and tutorials but I can't wrap my head around how I can apply it to my specific program to get the results without all of these individual if-statements.
epTitles1 = {"1" : "The Gang Gets Racist",
"2" : "Charlie Wants an Abortion",
"3" : "Underage Drinking: A National Concern",
"4" : "Charlie Has Cancer",
"5" : "Gun Fever",
"6" : "The Gang Finds a Dead Guy",
"7" : "Charlie Got Molested"}
epTitles2 = {"1" : "Charlie Gets Crippled",
"2" : "The Gang Goes Jihad",
"3" : "Dennis and Dee Go on Welfare",
"4" : "Mac Bangs Dennis' Mom" ,
"5" : "Hundred Dollar Baby" ,
"6" : "The Gang Gives Back",
"7" : "The Gang Exploits a Miracle",
"8" : "The Gang Runs for Office",
"9" : "Charlie Goes America All Over Everybody's Ass",
"10" : "Dennis and Dee Get a New Dad"}
x = int(input("Enter a season between 1 and 13 or 0 for random season: "))
print("You selected season:", x)
if x == 0:
randomSeason = random.randint(1,13)
print("Random season:", randomSeason)
if randomSeason == 1:
episode = random.randint(1,7)
print("Episode:", episode)
if episode == 1:
print(epTitles1["1"])
elif episode == 2:
print(epTitles1["2"])
elif episode == 3:
print(epTitles1["3"])
elif episode == 4:
print(epTitles1["4"])
elif episode == 5:
print(epTitles1["5"])
elif episode == 6:
print(epTitles1["6"])
elif episode == 7:
print(epTitles1["7"])
if randomSeason == 2:
episode = random.randint(1,10)
print("Episode:", episode)
if episode == 1:
print(epTitles2["1"])
elif episode == 2:
print(epTitles2["2"])
elif episode == 3:
print(epTitles2["3"])
elif episode == 4:
print(epTitles2["4"])
# same pattern continues for each season (13 seasons)
I would just like to learn and understand what kind of method/approach would help condense my code in a more practical way and how to do it.
Store your data inside a dict of dicts. Outer dict references the seasons, inner dict has the part-number and the title of this part:
import random
# see below for a user input safe variant
def get_random_title_of_radnom_season(data):
season = random.choice(list(data)) # replace with int numeric user input
nr = random.choice(list(data)) # replace with int numeric user input
title = data.get(season, {0:"does not exists"}.get(nr,0)
return f"Season {season} title {nr} was {title}"
# first index is the season, its value is a dict with partnr, title
d = {1 : { a: f"Title {a}" for a in range(1,15) },
2 : { a: f"Title {a}" for a in range(1,10) },
3 : { a: f"Title {a}" for a in range(1,4) } }
print(get_random_title_of_radnom_season(d))
This is how your data looks after expanding the dict comprehensions:
{1: {1: 'Title 1', 2: 'Title 2', 3: 'Title 3',
4: 'Title 4', 5: 'Title 5', 6: 'Title 6',
7: 'Title 7', 8: 'Title 8', 9: 'Title 9',
10: 'Title 10', 11: 'Title 11', 12: 'Title 12',
13: 'Title 13', 14: 'Title 14'},
2: {1: 'Title 1', 2: 'Title 2', 3: 'Title 3',
4: 'Title 4', 5: 'Title 5', 6: 'Title 6',
7: 'Title 7', 8: 'Title 8', 9: 'Title 9'},
3: {1: 'Title 1', 2: 'Title 2', 3: 'Title 3'}}
Multiple outputs:
Season 3 title 3 was Title 3
Season 3 title 1 was Title 1
Season 3 title 2 was Title 2
Season 2 title 4 was Title 4
Season 1 title 9 was Title 9
You could also look into using named tuples if you do not like "naked" dictionaries.
To make it user input proof instead of using randoms from the dict:
def get_user_title_of_radnom_season(data, season, nr):
title = data.get(season, {}).get(nr,False)
return f"Season {season} title {nr} was {title}" if title else "Does not exist"
print(get_user_title_of_radnom_season(d, 99, 99))
Will print "Does not exist" for any keys that are not appropriate
You can make your dictionaries this way
epTitles1 = {1:"s1ep1", 2:"s1ep2", 3:"s1ep3"}
epTitles1 = {1:"s2ep1", 2:"s2ep2", 3:"s2ep3"}
or you can even have a single dictionary of lists ( or list of lists) for all of the seasons
epTitles = { 1:["s1ep1", "s1ep2", "s1ep3"], 2:["s2ep1", "s2ep2", "s2ep3"] }
Then you can access them this way
print("You selected season:", x)
if x == 0:
randomSeason = random.randint(1,13)
print("Random season:", randomSeason)
episode = random.randint(1,7)
print("Episode:", epTitles[randomSeason][episode-1])
You can also have the episodes ranges for random selection saved in a dict of tuples to minimize the code even more, so the final code will be like this
epTitles = { 1:["s1ep1", "s1ep2", "s1ep3"], 2:["s2ep1", "s2ep2", "s2ep3"] }
epRanges = { 1:(1,7), 2:(1,10) }
x = int(input("Enter a season between 1 and 13 or 0 for random season: "))
print("You selected season:", x)
if x == 0:
randomSeason = random.randint(1,13)
print("Random season:", randomSeason)
episode = random.randint(epRanges[randomSeason][0], epRanges[randomSeason][1])
print("Episode:", epTitles[randomSeason][episode-1])
Thanks for all the suggestions! I was able to drastically shorten it by putting all the episodes in a single dictionary and used tuples as the keys. Then I was able to filter out the keys based on the users input and print out the season and episode's title

How to find what number argument was chosen with the input statement?

The variable or the types and the costs:
pasta_types = "Lasagne, Spaghetti, Macaroni, Cannelloni, Ravioli, Penne, Tortellini, Linguine, Farfalle, Fusilli"
pasta_costs = "6.00, 4.00, 3.15, 8.50, 9.00, 3.15, 5.00, 4.00, 4.25, 4.75"
The function to see if the in put has a type of pasta that is in the varaible:
def inventory(pt):
return(pt.title() in pasta_types)
Input:
type = input('What pasta would you like: Lasagne, Spaghetti, Macaroni, Cannelloni, Ravioli, Penne, Tortellini, Linguine, Farfalle, and Fusilli ')
Calling Function:
have = inventory(type)
How do I find out what number of the argument that was chosen?
Here's an example of doing something like that which builds and uses a dictionary that associates the name of each pasta type with its cost:
pasta_types = "Lasagne, Spaghetti, Macaroni, Cannelloni, Ravioli, Penne, Tortellini, " \
"Linguine, Farfalle, Fusilli"
pasta_costs = "6.00, 4.00, 3.15, 8.50, 9.00, 3.15, 5.00, 4.00, 4.25, 4.75"
# Create a dictionary associating (lowercase) pasta name to its (float) cost.
inventory = dict(zip(pasta_types.lower().replace(' ', '').split(','),
map(float, pasta_costs.replace(' ', '').split(','))))
## Display contents of dictionary created.
#from pprint import pprint
#print('inventory dictionary:')
#pprint(inventory)
while True:
pasta_type = input('What pasta would you like: ' + pasta_types + '?: ')
if pasta_type.lower() in inventory:
break # Got a valid response.
else:
print('Sorry, no {!r} in inventory, please try again\n'.format(pasta_type))
continue # Restart loop.
print('{} costs {:.2f}'.format(pasta_type, inventory[pasta_type]))

How to print list of lists without extra brackets and quotes?

I'm working on assignment for my Python 3 programming class. It's a database to look up movies and the year they came out. However, I'm having a hard time printing the output without extra brackets and quotes:
# Build a dictionary containing the specified movie collection
list_2005 = [["Munich", "Steven Spielberg"]]
list_2006 = [["The Departed", "Martin Scorsese"], ["The Prestige", "Christopher Nolan"]]
list_2007 = [["Into the Wild", "Sean Penn"]]
movies = {
'2005': list_2005,
'2006': list_2006,
'2007': list_2007
}
# Prompt the user for a year
# Displaying the title(s) and directors(s) from that year
user_year = str(input("Enter a year between 2005 and 2007:\n"))
if user_year in movies:
for name in movies[user_year]:
print("%s" % ', '.join(name))
print()
elif user_year not in movies:
print("N/A")
# Display menu
user_choice = ''
while user_choice != 'q':
print("MENU\nSort by:\ny - Year\nd - Director\nt - Movie title\nq - Quit")
print()
user_choice = str(input("Choose an option:\n"))
if user_choice == 'y':
for key, value in sorted(movies.items()):
print("%s:" % key)
print(" %s" % ''.join(str(movies[key])))
# Carry out the desired option: Display movies by year,
# display movies by director, display movies by movie title, or quit
I would like this output to be:
2005:
Munich, Steven Spielberg
2006:
The Prestige, Christopher Nolan
The Departed, Martin Scorsese
etc.
The output I am getting:
2005:
['Munich', 'Steven Spielberg']
2006:
[['The Prestige', 'Christopher Nolan'], ['The Departed', 'Martin Scorsese']]
etc.
Replace
print(" %s" % ''.join(str(movies[key])))
with
print("\t" + '\n\t'.join("{}, {}".format(m[0], m[1]) for m in movies[key]))

Categories