简体   繁体   中英

Nested for loops iterating over multiple dictionaries, is there an easier way?

So my lazy rear is trying to create a meal plan generator in python 3.x so I don't have to spend 30min every Friday figuring out what I should eat, but I'm new to coding and struggling with something. I'm still going through the Udemy course, but I wanted to get my fingers dirty with code to properly learn. Anywho, here's what I've got so far:

class Meals():

    def __init__(self,breakfast,lunch,dinner):
        self.breakfast=breakfast
        self.lunch=lunch
        self.dinner=dinner
    def __str__(self):
        return f"Breakfast will be {self.breakfast}.\nLunch will be        {self.lunch}.\nDinner will be {self.dinner}."
    def cost(self):
        day_meals=[self.breakfast,self.lunch,self.dinner]
        day_cost=0
        for i in day_meals:
            for ingredient in i:
                for key,value in Shop2.items():
                    if key in ingredient:
                        day_cost+=value
        return f"Today will cost £{round(day_cost,2)}."

If I do:

    monday_meals=Meals(random.choice(list(breakfasts.keys())),random.choice(list(lunches.keys())),random.choice(list(dinners.keys())))

And then call monday_meals.breakfast, then I get the result I want, the randomly chosen key from the 'breakfast' dictionary, but whenever I call for: monday_meals.cost() then I get £0 with no errors showing.

For reference, my testing dictionaries are as follows:

breakfasts={"a bowl of Rice Crispies":["cereal_1","milk"],"Weetabix":["cereal_2","milk"],"some Golden Grahams":["cereal_3","milk"],"toast":["bread","butter"],"scrambled eggs":["egg","egg","milk"]}

lunches={"cereal bars":["cereal_bar","cereal_bar"],"a boring ham sandwich":["bread","ham"],"some fruit":["banana","apple"],"salad":"salad_bag"}

dinners={"Student Meal #1":["mince","red_sauce","pepper","onion"],"Student Meal #2":["c_breast","white_sauce","onion","pepper"],"Student Meal #3":["egg","pepper","tomato","onion"]}

Shop2={"egg":0.3,"tomato":0.35,"pepper":0.33,"onion":0.4,"mince":1.2,"c_breast":0.7,"rice":0.8,"red_sauce":1.4,"white_sauce":1.5,"cereal_1":0.4,"milk":0.13,"cereal_2":0.35,"cereal_3":0.45,"bread":0.04,"butter":0.04,"cereal_bar":0.75,"ham":0.25,"banana":0.3,"apple":0.3,"salad":0.75}

I'd really appreciate any help with finding an easier way to calculate the cost of a day's meals.

You can implement your design with:

# inside your class:

@staticmethod
def calculate_meal_cost(ingredients, shopdict):
    return sum(shopdict[ingredient] for ingredient in ingredients)

@property
def cost(self):
    breakfast_cost = self.calculate_meal_cost(breakfasts[self.breakfast], Shop2)
    lunch_cost = self.calculate_meal_cost(lunches[self.lunch], Shop2)
    dinner_cost = self.calculate_meal_cost(dinners[self.dinner], Shop2)
    return breakfast_cost + lunch_cost + dinner_cost

Then:

meal = Meal(...)  # however you pick your meals is fine
meal.cost  # note: no parens

The problem is in what you pass in when you instantiate the class. breakfasts.keys() just gives you the keys of the dict, as the name implies: the keys are the things to the left of the colon, eg "a bowl of Rice Crispies". The actual ingredients are the values , but these never get sent to the Meals instance; so when you iterate through the "ingredients" you're actually iterating through the letters of the key.

You could fix this by using .values() instead of .keys() there, although a nicer way might be to pass both key and value so that your __str__ method outputs the description, not the ingredients; I'll leave that as an exercise...

Your Meals object is being initialized with the String name of the meal (eg random choice of breakfasts.keys() might be "Weetabix").

When you iterate through day_meals and do "ingredient in i", you are actually iterating through each "character" of Weetabix, so your ingredients would be "W" "e" "e" .. and so on.

Instead, you may want to initialize Meals with a choice of breakfasts.items(). Then you would have a tuple, eg ("Weetabix",["cereal_2","milk"]), in self.breakfast.

You can then unpack this in your loop:

for name,ingredients in day_meals:
   for i in ingredients:
      # and so on..

After you create Meals object, you have to call cost method. For now you only create object. Try:

monday_meals=Meals(random.choice(list(breakfasts.keys())),random.choice(list(lunches.keys())),random.choice(list(dinners.keys())))
print monday_meals.cost()
print monday_meals

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM