Tracks
/
Python
Python
/
Ejercicios
/
Mesero de banquetes
Mesero de banquetes

Mesero de banquetes

Ejercicio de aprendizaje

Introducción

Un conjunto es una colección mutable y desordenada de objetos hashables. Los miembros de un conjunto deben ser distintos: no se permiten elementos duplicados. Pueden contener varios tipos de datos distintos e incluso estructuras anidadas, como una tuple de tuples, siempre que todos los elementos se puedan hashear. Los conjuntos también existen en una versión inmutable: los frozensets.

Los conjuntos se usan sobre todo para eliminar duplicados rápidamente de otras estructuras de datos o agrupaciones de elementos. También se usan para hacer comparaciones eficientes cuando no se necesita mantener un orden ni hacer seguimiento de duplicados.

Como otros tipos de colecciones (diccionarios, listas, tuplas), los sets admiten:

  • Iteración mediante for item in <set>
  • Comprobación de pertenencia mediante in y not in,
  • Cálculo de la longitud mediante len(), y
  • Copias superficiales mediante copy()

Los sets no admiten:

  • Ningún tipo de indexación
  • Orden mediante clasificación o inserción
  • Rebanado
  • Concatenación mediante +

Comprobar la pertenencia a un set tiene una complejidad temporal constante (en promedio), a diferencia de comprobarla en una list o un string, donde la complejidad temporal crece a medida que aumenta la longitud de los datos. Métodos como <set>.union(), <set>.intersection() o <set>.difference() también tienen una complejidad temporal constante (en promedio).

Literales de conjuntos

Un set se puede escribir directamente como un literal de conjunto, con llaves {} y comas entre los elementos. Los duplicados se omiten sin avisar:

>>> one_element = {'➕'}
{'➕'}

>>> multiple_elements = {'➕', '🔻', '🔹', '🔆'}
{'➕', '🔻', '🔹', '🔆'}

>>> multiple_duplicates =  {'Hello!', 'Hello!', 'Hello!', 
                            '¡Hola!','Привіт!', 'こんにちは!', 
                            '¡Hola!','Привіт!', 'こんにちは!'}
{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'}

Los literales de conjunto usan las mismas llaves que los literales de dict, así que necesitas usar set() para crear un set vacío.

El constructor de conjuntos

set() (el constructor de la clase set) se puede usar con cualquier iterable que se pase como argumento. Los elementos del iterable se recorren uno por uno y se agregan al set de forma individual. No se conserva el orden de los elementos y los duplicados se omiten sin avisar:

# To create an empty set, the constructor must be used.
>>> no_elements = set()
set()

# The tuple is unpacked & each element is added.  
# Duplicates are removed.
>>> elements_from_tuple = set(("Parrot", "Bird", 
                               334782, "Bird", "Parrot"))
{334782, 'Bird', 'Parrot'}

# The list is unpacked & each element is added.
# Duplicates are removed.
>>> elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 
                              7, 11, 7, 11, 13, 13])
{2, 3, 5, 7, 11, 13}

Trampas al crear conjuntos

Debido a su comportamiento de «desempaquetado», usar set() con un string puede resultar sorprendente:

# String elements (Unicode code points) are 
# iterated through and added *individually*.
>>> elements_string = set("Timbuktu")
{'T', 'b', 'i', 'k', 'm', 't', 'u'}

# Unicode separators and positioning code points 
# are also added *individually*.
>>> multiple_code_points_string = set('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}

Los conjuntos pueden contener distintos tipos de datos y tipos de datos anidados, pero todos los elementos de un set deben ser hashables:

# Attempting to use a list for a set member throws a TypeError
>>> lists_as_elements = {['🌈','💦'], 
                        ['☁️','⭐️','🌍'], 
                        ['⛵️', '🚲', '🚀']}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


# Standard sets are mutable, so they cannot be hashed.
>>> sets_as_elements = {{'🌈','💦'}, 
                        {'☁️','⭐️','🌍'}, 
                        {'⛵️', '🚲', '🚀'}}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

Trabajar con conjuntos

Los conjuntos tienen métodos que, en general, imitan las operaciones matemáticas de conjuntos. La mayoría (no todos) de estos métodos tienen un operador equivalente. Los métodos, en general, aceptan cualquier iterable como argumento, mientras que los operadores requieren que ambos lados de la operación sean sets o frozensets.

Conjuntos disjuntos

El método <set>.isdisjoint(<other_collection>) sirve para comprobar si los elementos de un set se superponen de algún modo con los elementos de otro set. El método acepta cualquier iterable o set como argumento. Devuelve True si los dos conjuntos no tienen ningún elemento en común, y False si comparten elementos. No tiene un operador equivalente:

# Both mammals and additional_animals are lists.
>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant']
>>> additional_animals = ['pangolin', 'panda', 'parrot', 
                          'lemur', 'tiger', 'pangolin']

# Animals is a dict.
>>> animals = {'chicken': 'white',
               'sparrow': 'grey',
               'eagle': 'brown and white',
               'albatross': 'grey and white',
               'crow': 'black',
               'elephant': 'grey', 
               'dog': 'rust',
               'cow': 'black and white',
               'tiger': 'orange and black',
               'cat': 'grey',
               'squirrel': 'black'}
               
# Birds is a set.
>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'}

# Mammals and birds don't share any elements.
>>> birds.isdisjoint(mammals)
True

# There are also no shared elements between 
# additional_animals and birds.
>>> birds.isdisjoint(additional_animals)
True

# Animals and mammals have shared elements.
# **Note** The first object needs to be a set or converted to a set
# since .isdisjoint() is a set method.
>>> set(animals).isdisjoint(mammals)
False

Subconjuntos y superconjuntos

<set>.issubset(<other_collection>) se usa para comprobar si cada elemento de <set> también está en <other_collection>. La forma con operador es <set> <= <other_set>:

# Both mammals and additional_animals are lists.
>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant']
>>> additional_animals = ['pangolin', 'panda', 'parrot', 
                          'lemur', 'tiger', 'pangolin']

# Animals is a dict.
>>> animals = {'chicken': 'white',
               'sparrow': 'grey',
               'eagle': 'brown and white',
               'albatross': 'grey and white',
               'crow': 'black',
               'elephant': 'grey', 
               'dog': 'rust',
               'cow': 'black and white',
               'tiger': 'orange and black',
               'cat': 'grey',
               'squirrel': 'black'}

# Birds is a set.
>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'}

# Set methods will take any iterable as an argument.
# All members of birds are also members of animals.
>>> birds.issubset(animals)
True

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issubset() is a set method.
>>> set(mammals).issubset(animals)
True

# Both objects need to be sets to use a set operator
>>> birds <= set(mammals)
False

# A set is always a loose subset of itself.
>>> set(additional_animals) <= set(additional_animals)
True

<set>.issuperset(<other_collection>) es lo inverso de .issubset(). Se usa para comprobar si cada elemento de <other_collection> también está en <set>. La forma con operador es <set> >= <other_set>:

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issuperset() is a set method.
>>> set(animals).issuperset(mammals)
True

# All members of animals do not show up as members of birds.
>>> birds.issuperset(animals)
False

# Both objects need to be sets to use a set operator
>>> birds >= set(mammals)
False

# A set is always a loose superset of itself.
>>> set(animals) >= set(animals)
True

Intersecciones de conjuntos

<set>.intersection(*<other iterables>) devuelve un nuevo set con los elementos que son comunes al set original y a todos los <others> (en otras palabras, el set donde todo se interseca). La versión con operador de este método es <set> & <other set> & <other set 2> & ... <other set n>:

>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea',
                 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', 
                 'Kaffir Lime','Kale','Lavender','Mint','Oranges',
                 'Oregano', 'Tarragon', 'Wild Bergamot'}

>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', 
              'Summer Squash', 'Okra','Shallots', 'Basil', 
              'Cilantro', 'Cumin', 'Sunflower', 'Chervil', 
              'Summer Savory'}

>>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro',
            'Curry Leaf','Fennel','Kaffir Lime','Lavender',
            'Marjoram','Mint','Oregano','Summer Savory', 
            'Tarragon','Wild Bergamot','Wild Celery',
            'Winter Savory']


# Methods will take any iterable as an argument.
>>> perennial_herbs = perennials.intersection(herbs)
{'Annatto', 'Asafetida', 'Curry Leaf', 'Fennel', 'Kaffir Lime',
 'Lavender', 'Mint', 'Oregano', 'Wild Bergamot','Winter Savory'}

# Operators require both groups be sets.
>>> annuals & set(herbs)
 {'Basil', 'Chervil', 'Marjoram', 'Cilantro'}

Uniones de conjuntos

<set>.union(*<other iterables>) devuelve un nuevo set con los elementos de <set> y de todos los <other iterables>. La forma con operador de este método es <set> | <other set 1> | <other set 2> | ... | <other set n>:

>>> perennials = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'}
>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'}
>>> more_perennials = ['Radicchio', 'Rhubarb', 
                      'Spinach', 'Watercress']

# Methods will take any iterable as an argument.
>>> perennials.union(more_perennials)
{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb',
'Spinach','Sweet Potato','Watercress'}

# Operators require sets.
>>> set(more_perennials) | perennials
{'Asparagus',
 'Broccoli',
 'Kale',
 'Radicchio',
 'Rhubarb',
 'Spinach',
 'Sweet Potato',
 'Watercress'}

Diferencias de conjuntos

<set>.difference(*<other iterables>) devuelve un nuevo set con los elementos del <set> original que no están en <others>. La versión con operador de este método es <set> - <other set 1> - <other set 2> - ...<other set n>.

>>> berries_and_veggies = {'Asparagus', 
                          'Broccoli', 
                          'Watercress', 
                          'Goji Berries', 
                          'Goose Berries', 
                          'Ramps', 
                          'Walking Onions', 
                          'Blackberries', 
                          'Strawberries', 
                          'Rhubarb', 
                          'Kale', 
                          'Artichokes', 
                          'Currants'}

>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps',
               'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes')

# Methods will take any iterable as an argument.
>>> berries = berries_and_veggies.difference(veggies)
{'Blackberries','Currants','Goji Berries',
 'Goose Berries', 'Strawberries'}

# Operators require sets.
>>> berries_and_veggies - berries
{'Artichokes','Asparagus','Broccoli','Kale',
'Ramps','Rhubarb','Walking Onions','Watercress'}

<set>.symmetric_difference(<other iterable>) devuelve un nuevo set que contiene los elementos que están en <set> O en <other>, pero no en ambos. La versión con operador de este método es <set> ^ <other set>:

>>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'}
>>> plants_2 = ('🌸','🌴', '🌺', '🌲', '🌻', '🌵')


# Methods will take any iterable as an argument.
>>> fruit_and_flowers = plants_1.symmetric_difference(plants_2)
>>> fruit_and_flowers
{'🌸', '🌺', '🍈', '🥑', '🥭','🌻' }


# Operators require both groups be sets.
>>> fruit_and_flowers ^ plants_1
{'🌲',  '🌸', '🌴', '🌵','🌺', '🌻'}

>>> fruit_and_flowers ^ set(plants_2)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
Note

La diferencia simétrica de más de dos conjuntos da como resultado un set que incluye tanto los elementos únicos de cada set COMO los elementos que comparten más de dos conjuntos de la serie (más detalles en el artículo de Wikipedia sobre diferencia simétrica).

Para obtener solo los elementos únicos de cada set de la serie, hay que reunir en un paso aparte las intersecciones entre todas las combinaciones de 2 conjuntos y quitarlas:

>>> one = {'black pepper','breadcrumbs','celeriac','chickpea flour',
           'flour','lemon','parsley','salt','soy sauce',
           'sunflower oil','water'}

>>> two = {'black pepper','cornstarch','garlic','ginger',
           'lemon juice','lemon zest','salt','soy sauce','sugar',
           'tofu','vegetable oil','vegetable stock','water'}

>>> three = {'black pepper','garlic','lemon juice','mixed herbs',
             'nutritional yeast', 'olive oil','salt','silken tofu',
             'smoked tofu','soy sauce','spaghetti','turmeric'}

>>> four = {'barley malt','bell pepper','cashews','flour',
            'fresh basil','garlic','garlic powder', 'honey',
            'mushrooms','nutritional yeast','olive oil','oregano',
            'red onion', 'red pepper flakes','rosemary','salt',
            'sugar','tomatoes','water','yeast'}

>>> intersections = (one & two | one & three | one & four | 
                     two & three | two & four | three & four)
...
{'black pepper','flour','garlic','lemon juice','nutritional yeast', 
'olive oil','salt','soy sauce', 'sugar','water'}

# The ^ operation will include some of the items in intersections, 
# which means it is not a "clean" symmetric difference - there
# are overlapping members.
>>> (one ^ two ^ three ^ four) & intersections
{'black pepper', 'garlic', 'soy sauce', 'water'}

# Overlapping members need to be removed in a separate step
# when there are more than two sets that need symmetric difference.
>>> (one ^ two ^ three ^ four) - intersections
...
{'barley malt','bell pepper','breadcrumbs', 'cashews','celeriac',
  'chickpea flour','cornstarch','fresh basil', 'garlic powder',
  'ginger','honey','lemon','lemon zest','mixed herbs','mushrooms',
  'oregano','parsley','red onion','red pepper flakes','rosemary',
  'silken tofu','smoked tofu','spaghetti','sunflower oil', 'tofu', 
  'tomatoes','turmeric','vegetable oil','vegetable stock','yeast'}

Instrucciones

Tú y tus socios dirigen una pequeña empresa de catering. Acaban de aceptar organizar un evento para un club de cocina local que presenta platillos «favoritos del club». El club tiene poca experiencia organizando eventos grandes y necesita ayuda con la organización, las compras, la preparación y el servicio. Decidiste escribir algunos scripts pequeños de Python para acelerar todo el proceso de planificación.

1. Limpia los ingredientes de los platillos

Las recetas del evento se agregaron desde distintas fuentes y sus ingredientes parecen tener entradas duplicadas (o más). ¡No quieres terminar comprando artículos de más! Antes de empezar con las compras y la cocina, hay que «limpiar» la lista de ingredientes de cada platillo.

Implementa la función clean_ingredients(<dish_name>, <dish_ingredients>), que recibe el nombre de un platillo y una list de ingredientes. Esta función debe devolver una tuple con el nombre del platillo como primer elemento, seguido del set de ingredientes sin duplicados.

>>> clean_ingredients('Punjabi-Style Chole', ['onions', 'tomatoes', 'ginger paste', 'garlic paste', 'ginger paste', 'vegetable oil', 'bay leaves', 'cloves', 'cardamom', 'cilantro', 'peppercorns', 'cumin powder', 'chickpeas', 'coriander powder', 'red chili powder', 'ground turmeric', 'garam masala', 'chickpeas', 'ginger', 'cilantro'])

>>> ('Punjabi-Style Chole', {'garam masala', 'bay leaves', 'ground turmeric', 'ginger', 'garlic paste', 'peppercorns', 'ginger paste', 'red chili powder', 'cardamom', 'chickpeas', 'cumin powder', 'vegetable oil', 'tomatoes', 'coriander powder', 'onions', 'cilantro', 'cloves'})

2. Cócteles y mocktails

El evento va a incluir tanto cócteles como «mocktails», bebidas mezcladas sin alcohol. Necesitas asegurarte de que las bebidas «mocktail» sean realmente sin alcohol y de que los cócteles sí incluyan alcohol.

Implementa la función check_drinks(<drink_name>, <drink_ingredients>), que recibe el nombre de una bebida y una list de ingredientes. La función debe devolver el nombre de la bebida seguido de «Mocktail» si la bebida no tiene ingredientes alcohólicos, y el nombre de la bebida seguido de «Cocktail» si la bebida incluye alcohol. Para los fines de este ejercicio, los cócteles solo incluirán alcoholes de la constante ALCOHOLS en sets_categories_data.py:

>>> from sets_categories_data import ALCOHOLS 

>>> check_drinks('Honeydew Cucumber', ['honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber'])
...
'Honeydew Cucumber Mocktail'

>>> check_drinks('Shirley Tonic', ['cinnamon stick', 'scotch', 'whole cloves', 'ginger', 'pomegranate juice', 'sugar', 'club soda'])
...
'Shirley Tonic Cocktail'

3. Categoriza los platillos

La lista de invitados incluye comensales con distintas necesidades alimenticias, y tu personal tendrá que separar los platillos en vegano, vegetariano, paleo, keto y omnívoro. Un platillo pertenece a una categoría solo si todos sus ingredientes aparecen en el conjunto de ingredientes de esa categoría.

Implementa la función categorize_dish(<dish_name>, <dish_ingredients>), que recibe el nombre de un platillo y un set con los ingredientes de ese platillo. La función debe devolver un string con el formato dish name: <CATEGORY> (la categoría de comida a la que pertenece el platillo). Todos los platillos que se te den «encajarán» en una de las categorías importadas de sets_categories_data.py (VEGAN, VEGETARIAN, PALEO, KETO u OMNIVORE).

>>> from sets_categories_data import VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE


>>> categorize_dish('Sticky Lemon Tofu', {'tofu', 'soy sauce', 'salt', 'black pepper', 'cornstarch', 'vegetable oil', 'garlic', 'ginger', 'water', 'vegetable stock', 'lemon juice', 'lemon zest', 'sugar'})
...
'Sticky Lemon Tofu: VEGAN'

>>> categorize_dish('Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'shrimp', 'bacon', 'avocado', 'chickpeas', 'fresh tortillas', 'sea salt', 'guajillo chile', 'slivered almonds', 'olive oil', 'butter', 'black pepper', 'garlic', 'onion'})
...
'Shrimp Bacon and Crispy Chickpea Tacos with Salsa de Guacamole: OMNIVORE'

4. Etiqueta los alérgenos y los alimentos restringidos

Algunos invitados tienen alergias y restricciones alimenticias adicionales. Hay que etiquetar o anotar estos ingredientes en cada platillo para que no causen problemas.

Implementa la función tag_special_ingredients(<dish>), que recibe una tuple con el nombre del platillo en la primera posición y una list o un set con los ingredientes de ese platillo en la segunda posición. Devuelve el nombre del platillo seguido del set de ingredientes que requieren una nota especial en la descripción del platillo. Los ingredientes de un platillo dentro de una list pueden tener duplicados o no. Para los fines de este ejercicio, todos los alérgenos o ingredientes especiales que hay que etiquetar están en la constante SPECIAL_INGREDIENTS importada de sets_categories_data.py.

>>> from sets_categories_data import SPECIAL_INGREDIENTS

>>> tag_special_ingredients(('Ginger Glazed Tofu Cutlets', ['tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice']))
...
('Ginger Glazed Tofu Cutlets', {'garlic','soy sauce','tofu'})

>>> tag_special_ingredients(('Arugula and Roasted Pork Salad', ['pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts', 'balsamic vinegar', 'onions', 'black pepper']))
...
('Arugula and Roasted Pork Salad', {'pork tenderloin', 'blue cheese', 'pine nuts', 'onions'})

5. Compila una «lista maestra» de ingredientes

Como preparación para hacer el pedido y las compras, tendrás que compilar una «lista maestra» de ingredientes para todo lo que está en el menú (las cantidades se llenan después).

Implementa la función compile_ingredients(<dishes>), que recibe una list de platillos y devuelve un set con todos los ingredientes de todos los platillos de la lista. Cada platillo individual se representa con su set de ingredientes.

dishes = [ {'tofu', 'soy sauce', 'ginger', 'corn starch', 'garlic', 'brown sugar', 'sesame seeds', 'lemon juice'},
           {'pork tenderloin', 'arugula', 'pears', 'blue cheese', 'pine nuts',
           'balsamic vinegar', 'onions', 'black pepper'},
           {'honeydew', 'coconut water', 'mint leaves', 'lime juice', 'salt', 'english cucumber'}]

>>> compile_ingredients(dishes)
...
{'arugula', 'brown sugar', 'honeydew', 'coconut water', 'english cucumber', 'balsamic vinegar', 'mint leaves', 'pears', 'pork tenderloin', 'ginger', 'blue cheese', 'soy sauce', 'sesame seeds', 'black pepper', 'garlic', 'lime juice', 'corn starch', 'pine nuts', 'lemon juice', 'onions', 'salt', 'tofu'}

6. Separa los aperitivos para pasarlos en bandejas

Los anfitriones te dieron una lista de platillos que quieren que prepares como aperitivos «de un bocado» para servirlos en bandejas. Necesitas sacarlos de la lista principal de platillos que se preparan como porciones más grandes.

Implementa la función separate_appetizers(<dishes>, <appetizers>), que recibe una list de nombres de platillos y una list de nombres de aperitivos. La función debe devolver la list de nombres de platillos sin los nombres de los aperitivos. Tanto la list <dishes> como la list <appetizers> podrían contener duplicados y quizá necesiten que se quiten los duplicados.

dishes =    ['Avocado Deviled Eggs','Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups',
             'Grilled Flank Steak with Caesar Salad','Vegetarian Khoresh Bademjan','Avocado Deviled Eggs',
             'Barley Risotto','Kingfish Lettuce Cups']
          
appetizers = ['Kingfish Lettuce Cups','Avocado Deviled Eggs','Satay Steak Skewers',
              'Dahi Puri with Black Chickpeas','Avocado Deviled Eggs','Asparagus Puffs',
              'Asparagus Puffs']
              
>>> separate_appetizers(dishes, appetizers)
...
['Vegetarian Khoresh Bademjan', 'Barley Risotto', 'Flank Steak with Chimichurri and Asparagus', 
 'Grilled Flank Steak with Caesar Salad']

7. Encuentra los ingredientes que se usan en una sola receta

Dentro de cada categoría (vegana, vegetariana, paleo, keto, omnívora), vas a sacar los ingredientes que aparecen en un solo platillo. A estos ingredientes «singleton» se les asignará un comprador especial para asegurarse de que no se olviden en la prisa por terminar todo lo demás.

Implementa la función singleton_ingredients(<dishes>, <INTERSECTIONS>), que recibe una list de platillos y una constante <CATEGORY>_INTERSECTIONS para la misma categoría. Cada platillo se representa con un set de sus ingredientes. Cada <CATEGORY>_INTERSECTIONS es un set de ingredientes que aparecen en más de un platillo de la categoría. Usando operaciones de conjuntos, tu función debe devolver un set de ingredientes «singleton» (ingredientes que aparecen en un solo platillo de la categoría).

from sets_categories_data import example_dishes, EXAMPLE_INTERSECTION

>>> singleton_ingredients(example_dishes, EXAMPLE_INTERSECTION)
...
{'garlic powder', 'sunflower oil', 'mixed herbs', 'cornstarch', 'celeriac', 'honey', 'mushrooms', 'bell pepper', 'rosemary', 'parsley', 'lemon', 'yeast', 'vegetable oil', 'vegetable stock', 'silken tofu', 'tofu', 'cashews', 'lemon zest', 'smoked tofu', 'spaghetti', 'ginger', 'breadcrumbs', 'tomatoes', 'barley malt', 'red pepper flakes', 'oregano', 'red onion', 'fresh basil'}
Editar en GitHub El enlace se abre en una ventana o una pestaña nuevas
Python Exercism

¿Todo listo para empezar Mesero de banquetes?

Regístrate en Exercism para aprender y dominar Python con 17 conceptos146 ejercicios y mentoría humana real, todo gratis.