Reputation: 47
I've encountered a simple python problem to solve: Having lists of 3 categories of items and their corresponding values, print out all combinations across the 3 lists which have lower total value than X. (Code example might be clearer explanation).
I have managed to solve this using zip() and itertools.product() to create the combos, but when it comes to outputting the right combos, I feel like there has to be a better, more pythonic way to express the output by zipping the inner tuples of the products to get the sum of prices without needing to create 2 explicit genrators/list (the use case does not matter in this case I believe). Coming from a Java background, I'm still having problems at times not lapsing into Java-like syntax which is what I definitely want to avoid with Python.
Here is my code:
import itertools
# Print out all possible meal combinations under $30
main_courses = ['beef stew', 'fried fish']
price_main_courses = [28, 23]
desserts = ['ice-cream', 'cake']
price_desserts = [2, 4]
drinks = ['cola', 'wine']
price_drinks = [3, 10]
products = itertools.product(
zip(main_courses, price_main_courses),
zip(desserts, price_desserts),
zip(drinks, price_drinks)
)
for combo in products:
names = (x[0] for x in combo)
price = sum((x[1] for x in combo))
if price <= 30:
print(*names, price)
Upvotes: 2
Views: 84
Reputation: 17322
you could use a list comprehension
result = [(m, de, dr) for (m, mp), (de, dep), (dr, drp) in products if mp + dep + drp <= 30 ]
or you could manipulate your data structure by using a dict
to store the name of your products and the prices instead of using 2 lists:
import itertools
# Print out all possible meal combinations under $30
main_courses_price = {'beef stew': 28, 'fried fish': 23}
desserts_price = {'ice-cream': 2, 'cake': 4}
drinks_price = {'cola': 3, 'wine': 10}
full_prices = {**main_courses_price, **desserts_price, **drinks_price}
products = itertools.product(main_courses_price, desserts_price, drinks_price)
print(*(t for t in products if sum(map(full_prices.get, t)) <= 30), sep='\n')
output:
('fried fish', 'ice-cream', 'cola')
('fried fish', 'cake', 'cola')
Upvotes: 1
Reputation: 4510
Mmm, the only different thing that I would do is using list comprehensions instead of the for loop, for example:
import itertools
# Print out all possible meal combinations under $30
main_courses = ['beef stew', 'fried fish']
price_main_courses = [28, 23]
desserts = ['ice-cream', 'cake']
price_desserts = [2, 4]
drinks = ['cola', 'wine']
price_drinks = [3, 10]
products = itertools.product(
zip(main_courses, price_main_courses),
zip(desserts, price_desserts),
zip(drinks, price_drinks)
)
combos = [
combo for combo in products if sum(price for name, price in combo) <= 30
]
for combo in combos:
print(' + '.join(name for name, price in combo), '=', sum(price for name, price in combo))
>>> "fried fish + ice-cream + cola = 28"
>>> "fried fish + cake + cola = 30"
Upvotes: 1
Reputation: 10959
Based on this the for-loop can be written as:
for combo in products:
names, prices = zip(*combo)
price = sum(prices)
if price <= 30:
print(*names, price)
Upvotes: 2