Reputation: 61
It should be basic I suppose...
How do i iterate on my ingredients?
I have a dictionary that composed of lists of tuples, like so:
menu = {
'breakfast menu': [('eggs', 'milk', 'tomato', 'bread'), ('pancake', 'syrup', 'berries', 'coffee'), ('cereal', 'milk'),
('chicken', 'rice', 'cucumber', 'orange juice')],
'lunch menu': [('steak', 'potatoes', 'red wine'), ('fish', 'chips',
'beer'), ('spaghetti', 'sauce', 'salmon'),
('burger', 'buns', 'tomato', 'lettuce')],
'diner menu': [('omelet', 'cheese', 'tuna', 'bread'), ('cookies', 'milk')]}
What i tried to do so is as below:
for food in menu:
for meal in food:
for ingredient in meal:
print(menu[food][meal][ingredient])
The exception i get:
Traceback (most recent call last):
File "C:/Users/liore/PycharmProjects/manu/test.py", line 12, in <module>
print(menu[food][meal][ingredient])
TypeError: list indices must be integers or slices, not str
Thanks in advance:)
Upvotes: 0
Views: 86
Reputation: 11590
With a generator expression:
gen = (i for m in menu.values()
for f in m
for i in f)
for i in gen:
print(i)
Which produces the ingredients
eggs
milk
tomato
bread
pancake
syrup
berries
coffee
cereal
milk
chicken
rice
cucumber
orange juice
steak
potatoes
red wine
fish
chips
beer
spaghetti
sauce
salmon
burger
buns
tomato
lettuce
omelet
cheese
tuna
bread
cookies
milk
Your idea was in the right direction, but python allows to directly access the elements of the object you want to iterate on. That removes the need to access such element via indexing it on the object, although that option is always available.
Pythons's basic key features are protocols (e.g. iteration, context, etc.) and namespaces (i.e. variables and names, scope rules, classes, etc)
In this specific case I have used a generator, which generates the ingredients by iterating on the menu (a dictionary), on each of its meals (a list of foods) and on each of its foods (a tuple of ingredients).
Note: the generator can be iterated upon, i.e. it's also an iterator.
The nice aspect is that it yields the ingredients without creating another data structure, it simply drives through the data source (i.e. it iterates on it).
The catch is that it can only iterate once, as it's an iterator and not an iterable (like dictionaries, lists and tuples).
In case you need to use the sequence of the ingredients again, you can convert the generator expression into a list or create it as a list comprehension
Upvotes: 1
Reputation: 1107
I think this is what you are looking for -
for myMenu in menu:
for ingredient in menu[myMenu] :
for individualIngredient in ingrient:
print(individualIngredient)
Sample response
eggs
milk
tomato
bread
pancake
syrup
berries
coffee
cereal
milk
chicken
rice
cucumber
orange juice
steak
potatoes
red wine
fish
chips
beer
spaghetti
sauce
salmon
burger
buns
tomato
lettuce
omelet
cheese
tuna
bread
cookies
milk
Upvotes: 1
Reputation: 5757
You can try:
>>> for k,v in menu.items():
... for item in v:
... print(f'{k} - [{item}]')
...
breakfast menu - [('eggs', 'milk', 'tomato', 'bread')]
breakfast menu - [('pancake', 'syrup', 'berries', 'coffee')]
breakfast menu - [('cereal', 'milk')]
breakfast menu - [('chicken', 'rice', 'cucumber', 'orange juice')]
lunch menu - [('steak', 'potatoes', 'red wine')]
lunch menu - [('fish', 'chips', 'beer')]
lunch menu - [('spaghetti', 'sauce', 'salmon')]
lunch menu - [('burger', 'buns', 'tomato', 'lettuce')]
diner menu - [('omelet', 'cheese', 'tuna', 'bread')]
diner menu - [('cookies', 'milk')]
To get all the ingredients you can also try this :
>>> from itertools import chain
>>> for item in chain(menu.values()):
... print(item)
...
[('eggs', 'milk', 'tomato', 'bread'), ('pancake', 'syrup', 'berries', 'coffee'), ('cereal', 'milk'), ('chicken', 'rice', 'cucumber', 'orange juice')]
[('steak', 'potatoes', 'red wine'), ('fish', 'chips', 'beer'), ('spaghetti', 'sauce', 'salmon'), ('burger', 'buns', 'tomato', 'lettuce')]
[('omelet', 'cheese', 'tuna', 'bread'), ('cookies', 'milk')]
Upvotes: 1