From bf73c4bfe539f4043f240924d6ee7b28d906d6a0 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:46:00 -0700 Subject: [PATCH 01/34] Added cater-waiter UUID and exercise information. --- config.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config.json b/config.json index a7639fae84..d7f351d09c 100644 --- a/config.json +++ b/config.json @@ -167,6 +167,14 @@ "concepts": ["numbers"], "prerequisites": ["basics"], "status": "beta" + }, + { + "slug": "cater-waiter", + "name": "Cater Waiter", + "uuid": "922f8d2d-87ec-4681-9654-4e0a36a558d4", + "concepts": ["sets"], + "prerequisites": ["basics", "dicts", "lists", "loops", "tuples"], + "status": "beta" } ], "practice": [ From b9f44eeebfae47ddb22dcc8e2c14399220cc5f25 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:46:49 -0700 Subject: [PATCH 02/34] Added cater-waiter exemplar file and exercise configuration. --- .../concept/cater-waiter/.meta/config.json | 11 +++ .../concept/cater-waiter/.meta/design.md | 68 +++++++++++++++++++ .../concept/cater-waiter/.meta/exemplar.py | 57 ++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 exercises/concept/cater-waiter/.meta/config.json create mode 100644 exercises/concept/cater-waiter/.meta/design.md create mode 100644 exercises/concept/cater-waiter/.meta/exemplar.py diff --git a/exercises/concept/cater-waiter/.meta/config.json b/exercises/concept/cater-waiter/.meta/config.json new file mode 100644 index 0000000000..57cd451eda --- /dev/null +++ b/exercises/concept/cater-waiter/.meta/config.json @@ -0,0 +1,11 @@ +{ + "blurb": "Learn about sets by managing the menus and ingredients for your catering company's event.", + "icon": "meetup", + "authors": ["bethanyg"], + "files": { + "solution": ["sets.py"], + "test": ["sets_test.py"], + "exemplar": [".meta/exemplar.py"], + "editor": ["sets_test_data.py", "sets_categories.py"] + } +} diff --git a/exercises/concept/cater-waiter/.meta/design.md b/exercises/concept/cater-waiter/.meta/design.md new file mode 100644 index 0000000000..c94d703c6c --- /dev/null +++ b/exercises/concept/cater-waiter/.meta/design.md @@ -0,0 +1,68 @@ +## Goal + +The goal of this exercise is to teach the basics of [`sets`][set type] (_set type_) in Python. + + +## Learning objectives + +* understand that a set is an **unordered collection of distinct hashable objects** +* create a `set` via constructor (`set()`) and literal (`{}`) +* de-dupe a list of elements by converting a sequence type such as a `list` to a `set` type +* check for a membership of an element in a given set via `in` +* set comparison functions and set comparison operators (`=<`, `>=`, `issubset()`, `issuperset()`, etc.) +* additional set operators (`union`, `intersection`, `difference`, and `symmetric_difference`) +* add values to a given set via `add()` +* remove values from a given set via `discard()` +* iterate through a given set by using `for item in ` and `for index, item in enumerate()` +* understand that iterating through a set twince may result in a different iteration order (_sets are unordered_) + +## Out of scope + +* `frozenset()` +* `clear()` to delete all elements of a set +* check the length of a given set via `len()` +* `remove` as opposed to `discard` (_`remove` tosses a `keyerror` if the element is not present_) +* all forms/variants of `update()` +* remove (and use) a value from a given set via `pop()` +* make shallow copy(s) of a given set via `copy()` +* using additional builtins such as `sorted()`, `min()`, or `map()` with a set +* set comprehensions + +## Concepts + +* `sets` +* [`hashable`][term-hashable] objects +* `set` comparisons +* `set` operations + +## Prerequisites + +* `basics` +* `booleans` +* `comparisons` +* `dicts` +* `lists` +* `loops` + +## Resources to refer to + +* [Set Types (Python Official Docs)][set types](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) +* [Hashable (Python Official Docs Glossary)][term-hashable] +* [immutable (Python Official Docs Glossary)][term-immutable] + +### Hints + +Hints should link to the `Sets` section of the Python docs tutorial: [Sets][sets-tutorial], or equivelent resources. + + +### After + +After, the student can explore comprehension syntax, although it will be taught in separate exercises. This would also be a good time to explore set comparisons via function &/or operator, or experimenting with the `issuperset()` & `issubset()` functions. + + + +[set type]: https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/set.md +[set types]: https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset +[sets-tutorial]: https://docs.python.org/3/tutorial/datastructures.html#sets +[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable +[term-immutable]: https://docs.python.org/3/glossary.html#term-immutable \ No newline at end of file diff --git a/exercises/concept/cater-waiter/.meta/exemplar.py b/exercises/concept/cater-waiter/.meta/exemplar.py new file mode 100644 index 0000000000..18571636e9 --- /dev/null +++ b/exercises/concept/cater-waiter/.meta/exemplar.py @@ -0,0 +1,57 @@ +from sets_categories import (VEGAN, + VEGETARIAN, + KETO, + PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + + +def clean_ingredients(dish_name, dish_ingredients): + return dish_name, set(dish_ingredients) + + +def check_drinks(drink_name, drink_ingredients): + if ALCOHOLS.isdisjoint(drink_ingredients): + return drink_name + ' Mocktail' + else: + return drink_name + ' Cocktail' + + +def categorize_dish(dish_name, dish_ingredients): + categories = ((VEGAN,'VEGAN'), (VEGETARIAN,'VEGETARIAN'), (KETO,'KETO'), (PALEO,'PALEO'), (OMNIVORE,'OMNIVORE')) + + for category in categories: + if set(dish_ingredients) <= category[0]: + return dish_name + ': ' + category[1] + + +def tag_special_ingredients(dish): + return dish[0], (SPECIAL_INGREDIENTS & set(dish[1])) + + +def compile_ingredients(dishes): + combined_ingredients = set() + + for ingredients in dishes: + combined_ingredients = combined_ingredients.union(ingredients) + + return combined_ingredients + + +def separate_appetizers(dishes, appetizers): + return list(set(dishes) - set(appetizers)) + + +def singleton_ingredients(dishes, intersections): + all_ingredients = set() + + for ingredients in dishes: + all_ingredients = all_ingredients ^ ingredients + + return all_ingredients - intersections From 53992bc208e472441cc6f07bc4bce60ea4365945 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:47:56 -0700 Subject: [PATCH 03/34] Added intro, instructions, and hints for cater-waiter. --- exercises/concept/cater-waiter/.docs/after.md | 167 ++++++++++ exercises/concept/cater-waiter/.docs/hints.md | 63 ++++ .../cater-waiter/.docs/instructions.md | 142 +++++++++ .../cater-waiter/.docs/introduction.md | 291 ++++++++++++++++++ 4 files changed, 663 insertions(+) create mode 100644 exercises/concept/cater-waiter/.docs/after.md create mode 100644 exercises/concept/cater-waiter/.docs/hints.md create mode 100644 exercises/concept/cater-waiter/.docs/instructions.md create mode 100644 exercises/concept/cater-waiter/.docs/introduction.md diff --git a/exercises/concept/cater-waiter/.docs/after.md b/exercises/concept/cater-waiter/.docs/after.md new file mode 100644 index 0000000000..af22c5ded1 --- /dev/null +++ b/exercises/concept/cater-waiter/.docs/after.md @@ -0,0 +1,167 @@ +# After + +In Python, a [tuple](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/tuple.md) is an immutable collection of items in _sequence_. Like most collections (_see the built-ins [`list`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/list.md), [`dict`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/dict.md) and [`set`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/set.md)_), tuples can hold any (or multiple) data type(s) -- including other tuples. Like any [sequence](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range), items are referenced by 0-based index number, and can be copied in whole or in part via _slice notation_. Tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). + +Tuples take up very little memory space compared to other collection types and have constant (_O(1)_) access time. However, they cannot be resized, sorted, or altered once created, so are less flexible when frequent changes or updates to data are needed. + +## Tuple Construction + +Tuples can be formed in multiple ways, using either the `tuple` class constructor or the `tuple` literal declaration. + +### Using the `tuple()` constructor empty or with an _iterable_: + +```python +>>> no_elements = tuple() +() + +#the string elements (characters) are iterated through and added to the tuple +>>> multiple_elements_string = tuple("Timbuktu") +('T', 'i', 'm', 'b', 'u', 'k', 't', 'u') + +>>> multiple_elements_list = tuple(["Parrot", "Bird", 334782]) +("Parrot", "Bird", 334782) + +>>> multiple_elements_set = tuple({2, 3, 5, 7, 11}) +(2,3,5,7,11) + + +""" +The iteration default for dictionaries is over the keys. +To include both keys and values in a tuple made from a dictionary, use dict.items(), +which returns a list of (key, value) tuples. +""" +source_data = {"fish": "gold", "monkey": "brown"} +>>> multiple_elements_dict_1 = tuple(source_data) +('fish', 'monkey') + +>>> multiple_elements_dict_2 = tuple(source_data.items()) +(('fish', 'gold'), ('monkey', 'brown')) + + +""" +because the tuple constructor only takes _iterables_ (or nothing), it is much easier to create + a one-tuple via the literal method. +""" +>>> one_element = tuple([16]) +(16,) + +``` + +#### Declaring a tuple as a _literal_ : + +```python +>>> no_elements = () +() + +>>> one_element = ("Guava",) +("Guava",) + +>>> elements_separated_with_commas = "Parrot", "Bird", 334782 +("Parrot", "Bird", 334782) + +>>> elements_with_commas_and_parentheses = ("Triangle", 60, 60, 60) +("Triangle", 60, 60, 60) + +>>> nested_data_structures = ({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) +({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) + +#using the plus + operator unpacks each tuple and creates a new tuple. +>>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") +("George", 5, "cat", "Tabby") + +#likewise, using the multiplication operator * is the equvilent of using + n times +>>> first_group = ("cat", "dog", "elephant") + +>>> multiplied_group = first_group * 3 +('cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant') + +``` + +Note that generally parentheses are not _required_ to create a `tuple` literal - only commas. Parentheses are required in cases of ambiguity, such as an empty or one-item tuple or where a function takes a tuple as an argument. + +## Tuples as related information + +Tuples are often used as _records_ containing heterogeneous data that is _organizationally_ or _conceptually_ related and treated as a single unit of information. + +```python + +>>> student_info = ("Alyssa", "grade 3", "female", 8 ) + +``` + +Tuples are also used when homogeneous immutable sequences of data are needed for [`hashability`](https://docs.python.org/3/glossary.html#hashable), storage in a set, or creation of keys in a dictionary. + +Note that while tuples are in most cases _immutable_, because they can contain _any_ data structure or object they can become mutable if any of their elements is a _mutable type_. Using a mutable data type within a tuple will make the enclosing tuple un-hashable. + +```python + +>>> cmyk_color_map = { + (.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292), + (0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01), + (.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E), + (0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C) + } + +>>>> unique_rgb_colors = { + (59, 178, 146), + (247, 127, 1), + (89, 16, 142), + (140, 0, 76), + (76, 0, 140) + } + +>>> teal_700 = hash((59, 178, 146)) + +>>> teal_700 = hash(("Pantone 228", [(140, 0, 76), 0x8C004C])) +Traceback (most recent call last): + File "", line 1, in +TypeError: unhashable type: 'list' + +``` + +## Accessing data inside a tuple + +Items inside tuples (_like the sequence types `string` and `list`_), can be accessed via 0-based index and _bracket notation_. Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). + +Items inside tuples can also be _iterated over_ in a loop using `for item in` syntax. + +```python + +>>> student_info = ("Alyssa", "grade 3", "female", 8 ) + +#name is at index 0 or index -4 +>>> student_name = student_info[0] +Alyssa + +>>> student_name = student_info[-4] +Alyssa + +#grade is at index 1 or index -3 +>>> student_grade = student_info[1] +'grade 3' + +>>> student_grade = student_info[-3] +'grade 3' + +#age is at index 3 or index -1 +>>> student_age_1 = student_info[3] +8 + +>>> student_age_2 = student_info[-1] +8 + + +>>> for item in student_info: +>>> print(item) + +.... +Alyssa +grade 3 +female +8 + +``` + +## Extended tuples and related data types + +Tuples are often used as _records_, but the data inside them can only be accessed via _position_/_index_. The [`namedtuple()`](https://docs.python.org/3/library/collections.html#collections.namedtuple) class in the [`collections`](https://docs.python.org/3/library/collections.html#module-collections) module extends basic tuple functionality to allow access of elements by _name_. Additionally, users can adapt a [`dataclass`](https://docs.python.org/3/library/dataclasses.html) to provide similar named attribute functionality, with a some [pros and cons](https://stackoverflow.com/questions/51671699/data-classes-vs-typing-namedtuple-primary-use-cases). diff --git a/exercises/concept/cater-waiter/.docs/hints.md b/exercises/concept/cater-waiter/.docs/hints.md new file mode 100644 index 0000000000..056dcceecb --- /dev/null +++ b/exercises/concept/cater-waiter/.docs/hints.md @@ -0,0 +1,63 @@ +# Hints + +## General + +- [Sets][sets] are mutable, unordered collections with no duplicate elements. +- Sets can contain any data type, but all elements within a set must be [hashable][hashable]. +- Sets are [iterable][iterable]. +- Sets are most often used to quickly dedupe other collections or for membership testing. +- Sets also support mathematical operations like `union`, `intersection`, `difference`, and `symmetric difference` + +## 1. Clean up Dish Ingredients + +- The `set()` constructor can take any [iterable][iterable] as an argument. [lists:python/lists](https://exercism.lol/tracks/python/concepts/lists) are iterable. +- Remember: [tuples:python/tuples](https://exercism.lol/tracks/python/concepts/tuples) can be formed using `(, )` or via the `tuple()` constructor. + +## 2. Cocktails and Mocktails + +- A `set` is _disjoint_ from another set if the two sets share no elements. +- The `set()` constructor can take any [iterable][iterable] as an argument. [lists:python/lists](https://exercism.lol/tracks/python/concepts/lists) are iterable. +- In Python, [strings:python/strings](https://exercism.lol/tracks/python/concepts/strings) can be concatenated with the `+` sign. + +## 3. Categorize Dishes + +- Using [loops:python/loops](https://exercism.lol/tracks/python/concepts/loops) to iterate through the available meal categories might be useful here. +- If all the elements of `` are contained within ``, then ` <= `. +- The method equivalent of `<=` is `.issubset()` +- [tuples:python/tuples](https://exercism.lol/tracks/python/concepts/tuples) can contain any data type, including other tuples. Tuples can be formed using `(, )` or via the `tuple()` constructor. +- Elements within [tuples:python/tuples](https://exercism.lol/tracks/python/concepts/tuples) can be accessed from the left using a 0-based index number, or from the right using a -1-based index number. +- The `set()` constructor can take any [iterable][iterable] as an argument. [lists:python/lists](https://exercism.lol/tracks/python/concepts/lists) are iterable. +- [strings:python/strings](https://exercism.lol/tracks/python/concepts/strings) can be concatenated with the `+` sign. + +## 4. Label Allergens and Restricted Foods + +- A set _intersection_ are the elements shared between `` and ``. +- The set method equivalent of `&` is `.intersection()` +- Elements within [tuples:python/tuples](https://exercism.lol/tracks/python/concepts/tuples) can be accessed from the left using a 0-based index number, or from the right using a -1-based index number. +- The `set()` constructor can take any [iterable][iterable] as an argument. [lists:python/lists](https://exercism.lol/tracks/python/concepts/lists) are iterable. +- [tuples:python/tuples](https://exercism.lol/tracks/python/concepts/tuples) can be formed using `(, )` or via the `tuple()` constructor. + +## 5. Compile a "Master List" of Ingredients + +- A set _union_ is where ` and `` are combined into a single `set` +- The set method equivalent of `|` is `.union()` +- Using [loops:python/loops](https://exercism.lol/tracks/python/concepts/loops) to iterate through the various dishes might be useful here. + +## 6. Pull out Appetizers for Passing on Trays + +- A set _difference_ is where the elements of `` are removed from ``, e.g. ` - `. +- The set method equivalent of `-` is `.difference()` +- The `set()` constructor can take any [iterable][iterable] as an argument. [lists:python/lists](https://exercism.lol/tracks/python/concepts/lists) are iterable. +- The [list:python/lists](https://exercism.lol/tracks/python/concepts/lists) constructor can take any [iterable][iterable] as an argument. Sets are iterable. + +## 7. Find Ingredients Used in Only One Recipe + +- A set _symmetric difference_ is where elements appear in `` or ``, but not **_both_** sets. +- A set _symmetric difference_ is the same as subtracting the `set` _intersection_ from the `set` _union_, e.g. `( | ) - ( & )` +- A _symmetric difference_ of more than two `sets` will include elements that are repeated more than two times across the input `sets`. To remove these cross-set repeated elements, the _intersections_ between set pairs needs to be subtracted from the symmetric difference. +- Using [loops:python/loops](https://exercism.lol/tracks/python/concepts/loops) to iterate through the various dishes might be useful here. + + +[hashable]: https://docs.python.org/3.7/glossary.html#term-hashable +[iterable]: https://docs.python.org/3/glossary.html#term-iterable +[sets]: https://docs.python.org/3/tutorial/datastructures.html#sets \ No newline at end of file diff --git a/exercises/concept/cater-waiter/.docs/instructions.md b/exercises/concept/cater-waiter/.docs/instructions.md new file mode 100644 index 0000000000..b94b2bdda3 --- /dev/null +++ b/exercises/concept/cater-waiter/.docs/instructions.md @@ -0,0 +1,142 @@ +# Instructions + +You and your business partners operate a small catering company. You've just agreed to run an event for a local cooking club that features "club favorite" dishes. The club is inexperienced in hosting large events, and needs help with organizing, shopping, prepping and serving. You've decided to write some small Python scripts to speed the whole planning process along. + +## 1. Clean up Dish Ingredients + +The event recipes were added from various sources and their ingredients appear to have duplicate (_or more_) entries -- you don't want to end up purchasing excess items! + Before the shopping and cooking can commence, each dish's ingredient list needs to be "cleaned". + +Implement the `clean_ingredients(, )` function that takes the name of a dish and a `list` of ingredients. + This function should return a `tuple` with the name of the dish as the first item, followed by the de-duped `set` of ingredients. + + +```python +>>> 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. Cocktails and Mocktails + +The event is going to include both cocktails and "mocktails" - mixed drinks _without_ the alcohol. + You need to ensure that "mocktail" drinks are truly non-alcoholic and the cocktails do indeed _include_ alcohol. + +Implement the `check_drinks(, )` function that takes the name of a drink and a `list` of ingredients. + The function should return the name of the drink followed by "Mocktail" if the drink has no alcoholic ingredients, and drink name followed by "Cocktail" if the drink includes alcohol. + For the purposes of this exercise, cocktails will only include alcohols from the ALCOHOLS constant in `categories.py`: + +```python +>>> from categories 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. Categorize Dishes + +The guest list includes diners with different dietary needs, and your staff will need to separate the dishes into Vegan, Vegetarian, Paleo, Keto, and Omnivore. + +Implement the `categorize_dish(, )` function that takes a dish name and a `set` of that dish's' ingredients. +The function should return a string with the `dish name: ` (_which meal category the dish belongs to_). +All dishes will "fit" into one of the categories imported from `categories.py` (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE). + +```python +>>> from categories 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. Label Allergens and Restricted Foods + +Some guests have allergies and additional dietary restrictions. +These ingredients need to be tagged/annotated for each dish so that they don't cause issues. + +Implement the `tag_special_ingredients()` function that takes a `tuple` with the dish name in the first position, and a `list` or `set` of ingredients for that dish in the second position. +Return the dish name followed by the `set` of ingredients that require a special note on the dish description. +Dish ingredients inside a `list` may or may not have duplicates. + For the purposes of this exercise, all allergens or special ingredients that need to be labeled are in the SPECIAL_INGREDIENTS constant imported from `categories.py`. + +```python +>>> from categories 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', 'pinenuts', 'balsamic vinegar', 'onions', 'black pepper'])) +... +('Arugula and Roasted Pork Salad', {'blue cheese', 'pinenuts', 'pork tenderloin'}) +``` + +## 5. Compile a "Master List" of Ingredients + +In preparation for ordering and shopping, you'll need to compile a "master list" of ingredients for everything on the menu (_quantities to be filled in later_). + +Implement the `compile_ingredients()` function that takes a `list` of dishes and returns a set of all ingredients in all listed dishes. +Each individual dish is represented by its `set` of ingredients. + +```python +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. Pull out Appetizers for Passing on Trays + +The hosts have given you a list of dishes they'd like prepped as "bite-sized" appetizers to be served on trays. + You need to pull these from the main list of dishes being prepared as larger servings. + +Implement the `separate_appetizers(, )` function that takes a `list` of dish names and a `list` of appetizer names. +The function should return the `list` of dish names with appetizer names removed. +Either the `` or `` `list` could contain duplicates and may require de-duping. + +```python +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. Find Ingredients Used in Only One Recipe + +Within in each category (_Vegan, Vegetarian, Paleo, Keto, Omnivore_), you're going to pull out ingredients that appear in only one dish. +These "singleton" ingredients will be assigned a special shopper to ensure they're not forgotten in the rush to get everything else done. + +Implement the `singleton_ingredients(, ``)` function that takes a `list` of dishes and a `_INTERSECTIONS` constant for the same category. +Each dish is represented by a `set` of its ingredients. +Each `_INTERSECTIONS` is a `set` of ingredients that appear in more than one dish in the category. +Using set operations, your function should return a `set` of "singleton" ingredients (_ingredients appearing in only one dish in the category_). + +```python +from categories import example_dishes, EXAMPLE_INTERSECTIONS + +>>> singleton_ingredients(example_dishes, EXAMPLE_INTERSECTION) +... +{'vegetable oil', 'vegetable stock', 'barley malt', 'tofu', 'fresh basil', 'lemon', 'ginger', 'honey', 'spaghetti', 'cornstarch', 'yeast', 'red onion', 'breadcrumbs', 'mixed herbs', 'garlic powder', 'celeriac', 'lemon zest', 'sunflower oil', 'mushrooms', 'silken tofu', 'smoked tofu', 'bell pepper', 'cashews', 'oregano', 'tomatoes', 'parsley', 'red pepper flakes', 'rosemary'} +``` diff --git a/exercises/concept/cater-waiter/.docs/introduction.md b/exercises/concept/cater-waiter/.docs/introduction.md new file mode 100644 index 0000000000..57d329cf67 --- /dev/null +++ b/exercises/concept/cater-waiter/.docs/introduction.md @@ -0,0 +1,291 @@ +# Sets + +A [`set`][type-set] is a mutable and _unordered_ collection of _hashable_ objects. +Items within a `set` are distinct and duplicate members are not allowed. +Like most collections, `sets` can hold any (or multiple) data type(s) -- as long as those types can be [hashed][hashable]. +Sets also come in an _immutable_ [`frozenset`][type-frozenset] flavor. + +Like other collections, `sets` support membership testing through `in`, length calculation through `len()`, shallow copies through `copy()`, and iteration via `for item in `. +_Unlike_ sequence type collections (_`string`, `list` & `tuple`_), `sets` are **neither ordered nor indexed**, and _do not support_ slicing, sorting, or other sequence-type behaviors. + +Sets are most commonly used to quickly dedupe groups of items. +They're also used for fast membership testing, finding supersets & subsets of items, and performing "set math" (_calculating union, intersection, difference & symmetric difference between groups of items._). + +Sets are more space-efficient than a keys-only dictionary and faster than a `list` or `array` for membership -- unless you need to keep track of sequenced or duplicated items. + +## Construction + +A `set` can be declared as a _set literal_ with curly `{}` brackets and commas between elements. + +```python +>>> one_element = {'πŸ˜€'} +>>> one_element +{'πŸ˜€'} + +>>> multiple_elements = {'πŸ˜€', 'πŸ˜ƒ', 'πŸ˜„', '😁'} +>>> multiple_elements +{'πŸ˜€', 'πŸ˜ƒ', 'πŸ˜„', '😁'} + +>>> multiple_duplicates = {'πŸ˜€', 'πŸ˜ƒ', 'πŸ˜„', '😁', 'πŸ˜ƒ', 'πŸ˜„'} +>>> multiple_duplicates +{'πŸ˜€', '😁', 'πŸ˜ƒ', 'πŸ˜„'} +``` + +Set literals use the same curly braces as `dict` literals, so the `set()` constructor must be used to declare an empty `set`. + +The `set()` constructor can also be used with any _iterable_ passed as an argument. +Elements inside the iterable are cycled through by the constructor and added to the `set` individually. +Order is not preserved and duplicates are silently omitted: + +```python +>>> no_elements = set() +>>> no_elements +set() + +# The tuple is unpacked and each distinct element is added. Duplicates are removed. +>>> multiple_elements_from_tuple = set(("Parrot", "Bird", 334782, "Bird", "Parrot")) +>>> multiple_elements_from_tuple +{334782, 'Bird', 'Parrot'} + +# The list is unpacked and each distinct element is added. +>>> multiple_elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 7, 11, 7, 11, 13, 13]) +>>> multiple_elements_from_set +{2, 3, 5, 7, 11} +``` + +Sets can hold heterogeneous datatypes, but all `set` elements must be _hashable_: + +```python + +>>> lists_as_elements = {['πŸ˜…','🀣'], ['πŸ˜‚','πŸ™‚','πŸ™ƒ'], ['😜', 'πŸ€ͺ', '😝']} + +Traceback (most recent call last): + + File "", line 1, in + lists_as_elements = {['πŸ˜…','🀣'], ['πŸ˜‚','πŸ™‚','πŸ™ƒ'], ['😜', 'πŸ€ͺ', '😝']} + +TypeError: unhashable type: 'list' + +# Standard sets are mutable, so they cannot be hashed. +>>> sets_as_elements = {{'πŸ˜…','🀣'}, {'πŸ˜‚','πŸ™‚','πŸ™ƒ'}, {'😜', 'πŸ€ͺ', '😝'}} +Traceback (most recent call last): + + File "", line 1, in + sets_as_elements = {{'πŸ˜…','🀣'}, {'πŸ˜‚','πŸ™‚','πŸ™ƒ'}, {'😜', 'πŸ€ͺ', '😝'}} + +TypeError: unhashable type: 'set' +``` + +## Working with Sets + +Sets implement methods that generally mimic [mathematical set operations][mathematical-sets]. +Most (_though not all_) of these methods can be performed using either operator(s) or method call(s). +Using operators requires that both inputs be `sets` or `frozensets`, while methods will generally take any iterable as an argument. + +### Fast Membership Testing + + +**Subsets**: `.issubset()` / ` <= ` + are used to check if every element in `` is also in ``. + +**Supersets**: `.issuperset()` / ` >= ` + are used to check the inverse -- if every element in `` is also in ``. + + +```python +>>> animals = {'chicken': 'white','sparrow': 'grey','eagle': 'brown and white', + 'albatross': 'grey and white','crow': 'black','elephant': 'grey', + 'dog': 'rust','cow': 'black and white','tiger': 'organge and black', + 'cat': 'grey','squirrel': 'black'} + +>>> mammals = {'squirrel','dog','cat','cow', 'tiger', 'elephant'} +>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'} + +# Methods will take any iterable as an argument +>>> mammals.issubset(animals) +True + +# A set is always a loose subset of itself +>>> animals <= animals +True + +>>> birds <= set(animals) +True + +>>> birds <= mammals +False +``` + + +The `.isdisjoint()` method is used to test if a `set` has **no elements in common** with another set or iterable. +It will accept any `iterable` or `set` as an argument, returning `True` if they are **disjoint**, `False` otherwise. +Note that for `dcts`, the iteration default is over`.keys()`. + +```python +>>> mammals = {'squirrel','dog','cat','cow', 'tiger', 'elephant'} +>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'} + +# Dictionary of animal names with colors +>>> 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'} + +# List of additional animals +>>> additional_animals = ['pangolin', 'panda', 'parrot', 'lemur', 'tiger', 'pangolin'] +... + +>>> mammals.isdisjoint(birds) +True + +>>> mammals.isdisjoint(animals) +False + +>>> birds.isdisjoint(additional_animals) +True + +>>> set(additional_animals).isdisjoint(animals) +False +``` + +### Operations Between Sets + +**Union**: `.union(*)` and ` | | | ... | ` return a new `set` with elements from `` and all ``. + +```python +>>> perennial_vegetables = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'} +>>> annual_vegetables = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'} + +>>> more_perennials = ['Radicchio', 'Rhubarb', 'Spinach', 'Watercress'] + +# Methods will take any iterable as an argument. +>>> perennial_vegetables.union(more_perennials) +{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb','Spinach','Sweet Potato','Watercress'} + +# Operators require sets. +>>> perennial_vegetables | annual_vegetables +{'Asparagus','Broccoli','Corn','Kale','Summer Squash','Sweet Peas','Sweet Potato','Zucchini'} + +``` + +**Difference**: `.difference(*)` and ` - - - ...` return a new `set` with elements from the original `` that are not in ``. + +```python +>>> berries_and_veggies = {'Asparagus', 'Broccoli', 'Watercress', 'Goji Berries', 'Goose Berries', 'Ramps', + 'Walking Onions', 'Raspberries','Blueberries', 'Blackberries', 'Strawberries', + 'Rhubarb', 'Kale', 'Artichokes', 'Currants', 'Honeyberries'} + +# Methods will take any iterable as an argument. +>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps', + 'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes') + +>>> just_berries = berries_and_veggies.difference(veggies) +>>> just_berries +{'Blackberries','Blueberries','Currants','Goji Berries', + 'Goose Berries','Honeyberries','Raspberries','Strawberries'} + +>>> berries_and_veggies - just_berries +{'Artichokes','Asparagus','Broccoli','Kale','Ramps','Rhubarb','Walking Onions','Watercress'} +``` + +**Intersection**: `.intersection(*)` and ` & & & ... ` return a new `set` with elements common to the original `set` and all ``. + +```python +>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea','Winter Savory', 'Blackberries','Broccoli','Curry Leaf', + 'Fennel','French Sorrel','Fuchsia','Kaffir Lime','Kale','Lavender','Mint','Oranges', + 'Oregano','Ramps','Roses','Tarragon','Watercress','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) +>>> perennial_herbs +{'Mint', 'Annatto', 'Winter Savory', 'Curry Leaf', 'Lavender', 'Fennel', + 'Oregano', 'Kaffir Lime','Asafetida', 'Wild Bergamot', 'Tarragon'} + +>>> annuals & set(herbs) + {'Basil', 'Chervil', 'Marjoram', 'Cilantro'} +``` + +**Symmetric Difference**: `.symmetric_difference()` and ` ^ ` return a new `set` that contains elements that are in `` OR ``, but **not in both**. + +```python +>>> 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'} + +>>> two_as_list = ['black pepper','cornstarch','garlic','ginger','lemon juice','lemon zest', + 'salt','soy sauce','sugar','tofu','vegetable oil','vegetable stock','water'] + +>>> one ^ two +... +{'breadcrumbs','celeriac','chickpea flour','cornstarch','flour','garlic','ginger', 'lemon', +'lemon juice','lemon zest','parsley','sugar','sunflower oil','tofu','vegetable oil','vegetable stock'} + +>>> (one | two) - (one & two) +... +{'breadcrumbs','celeriac','chickpea flour','cornstarch','flour','garlic','ginger', 'lemon', +'lemon juice','lemon zest','parsley','sugar','sunflower oil','tofu','vegetable oil','vegetable stock'} + +>>> one ^ two == (one | two) - (one & two) +... +True + + +# Methods will take any iterable as an argument. +>>> one.symmetric_difference(two_as_list) +... +{'breadcrumbs','celeriac','chickpea flour','cornstarch','flour','garlic','ginger', 'lemon', +'lemon juice','lemon zest','parsley','sugar','sunflower oil','tofu','vegetable oil','vegetable stock'} +``` + +A symmetric difference of more than two sets will result in a `set` that includes both the elements unique to each `set` AND elements shared between more than two sets in the series (_details in the Wikipedia article on [symmetric difference][symmetric_difference]_). +To obtain only items unique to each `set` in the series, intersections between all 2-set combinations need to be aggregated in a separate step, and removed. + +```python +>>> 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) +>>> intersections + ... + {'black pepper','flour','garlic','lemon juice','nutritional yeast', 'olive oil','salt','soy sauce', 'sugar','water'} + +>>> one ^ two ^ three ^ four +... +{'barley malt','bell pepper','black pepper','breadcrumbs','cashews','celeriac','chickpea flour','cornstarch', + 'fresh basil','garlic','garlic powder','ginger','honey','lemon','lemon zest','mixed herbs','mushrooms', + 'oregano','parsley','red onion','red pepper flakes','rosemary','silken tofu','smoked tofu','soy sauce', + 'spaghetti','sunflower oil','tofu','tomatoes','turmeric','vegetable oil','vegetable stock','water','yeast'} + +>>> (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'} +``` + +[symmetric_difference]: https://en.wikipedia.org/wiki/Symmetric_difference +[type-set]: https://docs.python.org/3/library/stdtypes.html#set +[type-frozenset]: https://docs.python.org/3/library/stdtypes.html#frozenset +[mathematical-sets]: https://en.wikipedia.org/wiki/Set_theory#Basic_concepts_and_notation +[hashable]: https://docs.python.org/3.7/glossary.html#term-hashable From ade83fcb79bb8e02c677bd91c323461c382e0ccd Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:50:46 -0700 Subject: [PATCH 04/34] Added stub, test, and test_data files. --- exercises/concept/cater-waiter/sets.py | 113 +++++ .../concept/cater-waiter/sets_categories.py | 227 +++++++++ exercises/concept/cater-waiter/sets_test.py | 109 +++++ .../concept/cater-waiter/sets_test_data.py | 457 ++++++++++++++++++ 4 files changed, 906 insertions(+) create mode 100644 exercises/concept/cater-waiter/sets.py create mode 100644 exercises/concept/cater-waiter/sets_categories.py create mode 100644 exercises/concept/cater-waiter/sets_test.py create mode 100644 exercises/concept/cater-waiter/sets_test_data.py diff --git a/exercises/concept/cater-waiter/sets.py b/exercises/concept/cater-waiter/sets.py new file mode 100644 index 0000000000..e0ae31bf1d --- /dev/null +++ b/exercises/concept/cater-waiter/sets.py @@ -0,0 +1,113 @@ +from sets_categories import (VEGAN, + VEGETARIAN, + KETO, PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + + +def clean_ingredients(dish_name, dish_ingredients): + ''' + + :param dish_name: str + :param dish_ingredients: list + :return: tuple of (dish_name, ingredient set) + + This function should return a `tuple` with the name of the dish as the first item, + followed by the de-duped `set` of ingredients as the second item. + ''' + + pass + + + +def check_drinks(drink_name, drink_ingredients): + ''' + + :param drink_name: str + :param drink_ingredients: list + :return: str drink name + ("Mocktail" or "Cocktail") + + The function should return the name of the drink followed by "Mocktail" if the drink has + no alcoholic ingredients, and drink name followed by "Cocktail" if the drink includes alcohol. + ''' + + pass + +def categorize_dish(dish_name, dish_ingredients): + ''' + + :param dish_name: str + :param dish_ingredients: list + :return: str "dish name: CATEGORY" + + This function should return a string with the `dish name: ` (which meal category the dish belongs to). + All dishes will "fit" into one of the categories imported from `categories.py` + (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE). + ''' + + pass + + +def tag_special_ingredients(dish): + ''' + + :param dish: tuple of (str of dish name, list of dish ingredients) + :return: tuple of (str of dish name, set of dish special ingredients) + + Return the dish name followed by the `set` of ingredients that require a special note on the dish description. + For the purposes of this exercise, all allergens or special ingredients that need to be tracked are in the + SPECIAL_INGREDIENTS constant imported from `categories.py`. + ''' + + pass + + + +def compile_ingredients(dishes): + ''' + + :param dishes: list of dish ingredient sets + :return: set + + This function should return a `set` of all ingredients from all listed dishes. + ''' + + pass + + + +def separate_appetizers(dishes, appetizers): + ''' + + :param dishes: list of dish names + :param appetizers: list of appetizer names + :return: list of dish names + + The function should return the list of dish names with appetizer names removed. + Either list could contain duplicates and may require de-duping. + ''' + + pass + + + +def singleton_ingredients(intersection, dishes): + ''' + + :param intersection: constant - one of (VEGAN_INTERSECTION,VEGETARIAN_INTERSECTION,PALEO_INTERSECTION, + KETO_INTERSECTION,OMNIVORE_INTERSECTION) + :param dishes: list of ingredient sets + :return: set of singleton ingredients + + Each dish is represented by a `set` of its ingredients. + Each `_INTERSECTION` is an `intersection` of all dishes in the category. + The function should return a `set` of ingredients that only appear in a single dish. + ''' + + pass diff --git a/exercises/concept/cater-waiter/sets_categories.py b/exercises/concept/cater-waiter/sets_categories.py new file mode 100644 index 0000000000..b23a91f798 --- /dev/null +++ b/exercises/concept/cater-waiter/sets_categories.py @@ -0,0 +1,227 @@ +VEGAN = { + 'chives', 'nutritional yeast', 'tomato', 'orange zest', 'pareve puff pastry', 'cashews', 'tofu', + 'rice vinegar', 'black pepper', 'cardamom powder', 'mustard seeds', 'parev shortcrust pastry', + 'scallions', 'water', 'chinese eggplants', 'lemon juice', 'smoked paprika', 'cloves', 'basmati rice', + 'cayenne pepper', 'green onions', 'sunflower oil', 'mixed herbs', 'garlic paste', 'parsley', + 'fresh red chili', 'flour', 'garlic', 'oregano', 'green beans', 'harissa', 'brandy', 'fresh basil', + 'coriander', 'vinegar', 'thyme', 'coriander seeds', 'clove powder', 'pomegranate seeds', + 'sugar', 'yukon gold potato', 'sesame oil', 'cinnamon powder', 'butternut squash', 'allspice powder', + 'red pepper flakes', 'soy sauce', 'sesame seeds', 'cornstarch', 'mango powder', 'vegetable stock', + 'raisins', 'barley malt', 'olive oil', 'ground almonds', 'white rice', 'garlic powder', 'walnuts', + 'saffron powder', 'red chili powder', 'turmeric powder', 'spring onions', 'yeast', 'khmeli suneli', + 'peanuts', 'bulgur', 'cilantro', 'onion', 'calabash nutmeg', 'black-eyed peas', 'grains of selim', + 'zucchini', 'currants', 'spaghetti', 'figs', 'red bell pepper', 'lemon zest', 'ground turmeric', + 'chili flakes', 'chickpea flour', 'hing', 'slivered almonds', 'vegetable oil', 'serrano chili', + 'salt', 'yellow onions', 'salt', 'coriander powder', 'orange zest', 'garam masala', 'yellow onion', + 'smoked tofu', 'bell pepper', 'apples', 'brown sugar', 'coconut oil', 'orange juice', + 'sorghum stems', 'dried blueberries', 'tomato paste', 'curry leaves', 'vegetarian worcestershire sauce', + 'hot water', 'fresh ginger', 'firm tofu', 'eggplants', 'bell pepper', 'siracha', 'carrot', 'nigella seeds', + 'vegan butter', "za'atar", 'baking soda', 'brown sugar', 'dried cranberries', 'kosher salt', 'mangoes', + 'vegan unsweetened yoghurt', 'black peppercorn', 'vinegar', 'dill', 'barberries', 'honey', 'tomatoes', + 'yellow split peas', 'persian cucumber', 'turmeric', 'lemon', 'cumin', 'oil', 'mushrooms', 'spring onion', + 'pomegranate concentrate', 'cumin seeds', 'balsamic vinegar', 'ripe plantains', 'celeriac', 'breadcrumbs', + 'ginger', 'dried cherries', 'red onion', 'rosemary', 'chopped parsley', 'corn', 'cumin powder', 'pecans', + 'silken tofu', 'pomegranate molasses', 'carrot', 'corn flour', 'mashed potatoes' + } + + +VEGETARIAN = { + 'almonds', 'chives', 'limes', 'puff pastry', 'onion', 'cashews', 'red cabbage', 'red wine vinegar', + 'brussel sprouts', 'fresh corn', 'black pepper', 'lemon juice', 'roasted corn', 'eggs', + 'fresh cilantro leaves', 'shiitake mushrooms', 'sunflower oil', 'sage', 'dijon mustard', + 'blanched almonds', 'dates', 'flour', 'fresh pea tendrils', 'garlic', 'egg', 'green beans', + 'yukon gold potato', 'vermicelli noodles', 'onions', 'avocado', 'dried lasagna noodles', + 'thyme', 'cauliflower', 'basil', 'watercress', 'black beans', 'butternut squash', 'red thai chili', + 'masa', 'red chili', 'red onions', 'jalapeΓ±o chili', 'grated nutmeg', 'feta cheese', 'hazelnuts', + 'soy sauce', 'shallots', 'chipotle chili', 'vegetable bullion', 'fresh cherry tomatoes', 'olive oil', + 'milk', 'fresh cherry bocconcini', 'crema', 'marmite', 'walnuts', 'nutmeg', 'ricotta cheese', + 'chestnuts', 'mint leaves', 'lime juice', 'white wine', 'apples', 'pearl barley', 'cotija cheese', + 'zucchini', 'currants', 'leek', 'pomegranate', 'lemon zest', 'avocados', 'parmesan cheese', 'mint', + 'leeks', 'fresh artichoke hearts', 'vegetable oil', 'brazil nuts', 'red chili', 'sharp white cheddar', + 'salt', 'pepitas', 'green lentils', 'beets', 'celery', 'smoked tofu', 'fresh tomatoes', + 'puff pastry sheets', 'palm sugar', 'vegetarian fish sauce', 'oil marinated artichokes', 'hot water', + 'chickpeas', 'firm tofu', 'wombok', 'carrot', 'asparagus', 'bean sprouts', 'kosher salt', + 'pasilla chili', 'tomatillos', 'parmesan rind', 'pasta sheets', 'cream', 'butter', 'croutons', + 'lacinato kale', 'fresh or frozen fava beans', 'fresh pumpkin', 'honey', 'tomatoes', 'olives', + 'capers', 'pine nuts', 'lemon', 'cumin', 'ancho chili', 'fresh peas', 'spring roll wrappers', + 'balsamic vinegar', 'portobello mushrooms', 'breadcrumbs', 'blue cheese', 'red onion', + 'rosemary', 'pecans', 'carrot', 'corn flour', 'toasted peanuts' + } + +PALEO = { + 'cinnamon', 'chiles de Γ‘rbol', 'chives', 'limes', 'allspice', 'zucchini', 'seranno chili', 'lemon zest', + 'apple cider vinegar', 'avocados', 'cashews', 'mango', 'cilantro leaves', 'pepitas', 'white chicken', + 'chipotles', 'black pepper', 'scallions', 'pumpkin puree', 'water', 'serrano chili', 'lemon juice', + 'smoked paprika', 'homemade apricot honey preserves', 'eggs', 'salt', 'flank steak', 'fresh cilantro leaves', + 'cider vinegar', 'cloves', 'purple sweet potato', 'coconut yogurt', 'green onions', 'tilapia', + 'yellow bell pepper', 'coconut oil', 'whole chicken', 'coconut oil', 'safflower oil', 'roma tomatoes', + 'fresh red chili', 'fresh thai chili', 'shrimp', 'garlic', 'onions', 'lime', 'avocado', 'fresh parsley', + 'cauliflower', 'shredded red cabbage', 'basil', 'baking soda', 'serrano chili', + 'cherry tomatoes', 'kale', 'bacon', 'kosher salt', 'mangoes', 'lacinato kale', 'shallots', 'pineapple', + 'chipotle chili', 'white vinegar', 'honey', 'tomatoes', 'homemade tamarind concentrate', + 'mexican oregano', 'olive oil', 'pine nuts', 'garlic powder', 'coconut flour', 'green bell pepper', + 'dried apricots', 'cumin', 'nutmeg', 'kosher salt', 'onions', 'mustard seed', 'lemons', 'lime zest', + 'ground cumin', 'almond butter', 'chili powder', 'lime juice', 'paleo mayonnaise', 'pork chops', + 'cilantro', 'onion', 'red bell pepper', 'paleo parmesan cheese', 'radishes', 'avocado oil', + 'dijon mustard', 'avocado mayonnaise', 'castelfranco radicchio', 'worcestershire sauce', 'treviso' + } + +KETO = { + 'cinnamon', 'avocado oil', 'chives', 'sriacha', 'almond flour', 'crunchy peanut butter', + 'cucumbers', 'cream cheese', 'red cabbage', 'red wine vinegar', 'brussel sprouts', 'black pepper', + 'cardamom powder', 'mustard seeds', 'scallions', 'kecap manis', 'lemon juice', 'eggs', 'tahini', + 'cloves', 'green onions', 'dijon mustard', 'garlic paste', 'watermelon radishes', 'parmesan', + 'parsley', 'star anise', 'fresh cucumber', 'fresh red chili', 'shrimp', 'garlic', 'oregano', + 'fennel bulb', 'harissa', 'dutch carrot', 'fresh basil', 'avocado', 'clove powder', 'coriander seeds', + 'thyme', 'fresh parsley', 'chicken', 'cauliflower', 'basil', 'watercress', 'cinnamon powder', + 'cherry tomatoes', 'soy sauce', 'sesame seeds', 'micro cilantro', 'mozzarella cheese', 'shallots', + 'mango powder', 'chipotle chili', 'olive oil', 'spinach', 'pink peppercorns', 'coconut flour', + 'salmon steaks', 'dark soy sauce', 'red chili powder', 'turmeric powder', 'spring onions', + 'lime juice', 'ginger garlic paste', 'pork chops', 'peanuts', 'dried fenugreek leaves', 'cilantro', + 'onion', 'salmon fillets', 'toasted buckwheat', 'whole small crimini mushrooms', 'caster sugar', + 'granny smith apples', 'green cabbage', 'apple cider vinegar', 'chili flakes', 'parmesan cheese', + 'hing', 'castelfranco radicchio', 'cilantro leaves', 'fresh greek yogurt', 'roasted chicken', 'ghee', + 'flaxmeal', 'flank steak', 'salt', 'coriander powder', 'boned chicken', 'red chili flakes', + 'garam masala', 'almond meal', 'peanut oil', 'tomato paste', 'oyster sauce', + 'curry leaves', 'fresh ginger', 'cardamom', 'radishes', 'little gem lettuce heads', + 'grilled king fish', 'carrot', 'cinnamon sticks', 'heavy cream', 'asparagus', 'nigella seeds', + 'light soy sauce', 'pork belly', 'green chili', 'mangoes', 'red and green thai chili', 'butter', + 'vinegar', 'dill', 'fish sauce', 'white vinegar', 'tomatoes', 'mirin', + 'avocado mayonnaise', 'turmeric', 'lemon', 'cumin', 'fennel seeds', 'lemon juice', 'salt', + 'roasted peanuts', 'ginger', 'red onion', 'rosemary', 'cumin powder', 'cashew nuts', 'pecans', + 'green chili','whole small crimini mushrooms', 'monk fruit', 'sour cream' + } + +OMNIVORE = { + 'clams', 'prawns', 'white wine vinegar', 'date syrup', 'limes', 'tomato', 'coriander', + 'black chickpeas', 'yellow bell pepper', 'black cardamom', 'baby squid', 'pepitas', + 'red cabbage', 'baby scallops', 'green cardamom', 'black pepper', 'chaat masala', 'water', + 'lemon juice', 'tahini', 'cloves', 'white pepper', 'fennel bulbs', 'tomato puree', + 'maggi cubes', 'couscous', 'yellow mustard', 'parsley', 'sriracha', 'roma tomatoes', + 'shrimp', 'garlic', 'oregano', 'chicken wings', 'yukon gold potato', 'harissa', 'onions', + 'avocado', 'thyme', 'chicken', 'sugar', 'flat-leaf parsley', 'celery seeds', 'cherry tomatoes', + 'mayonnaise', 'scallion chutney', 'red pepper flakes', 'hazelnuts', 'soy sauce', 'sesame seeds', + 'red snapper', 'white onion', 'vegetable bullion', 'marjoram', 'pani puri', 'olive oil', 'rice', + 'serrano chili', 'tamarind concentrate', 'lime juice', 'white wine', 'beef brisket', 'cilantro', + 'onion', 'crushed red pepper flakes', 'chiles de Γ‘rbol', 'fresh mint', 'zucchini', 'red bell pepper', + 'yoghurt', 'apple cider vinegar', 'parmesan cheese', 'slivered almonds', 'whole-milk yogurt', + 'anchovy fillets', 'fresh ricotta', 'mint', 'chile manzano', 'roasted chicken', 'sea salt', + 'fresh thyme', 'vegetable oil', 'salt', 'mexican crema', 'celery', 'yellow onion', + 'worcestershire sauce', 'fresh tortillas', 'tomato paste', 'oranges', 'chickpeas', + 'scotch bonnet pepper', 'shelled large shrimp', 'mussels', 'summer squash', 'salsa', + 'garlic cloves', 'fish stock', 'bell pepper', 'green bell pepper', 'carrot', 'cinnamon sticks', + 'thin sev', 'brown sugar', 'baby carrot', 'bacon', 'kosher salt', 'bay leaves', 'anaheim chili', + 'oaxaca cheese', 'butter', 'vinegar', 'crab legs', 'white vinegar', 'honey', 'tomatoes', + 'green cabbage', 'toasted bread', 'turmeric', 'lemon', 'cumin', 'black peppercorns', 'poblano chili', + 'arborio risotto rice', 'fresh corn tortillas', 'balsamic vinegar', 'rhubarb', 'ginger', + 'guajillo chile', 'filo pastry', 'leg of lamb', 'red onion', 'chipotle adobo sauce', 'rosemary', + 'chili powder', 'beer', 'carrot' + } + +SPECIAL_INGREDIENTS = {'cream','bacon', 'garlic', 'baby scallops', 'mussels', 'baby squid', 'cashews', 'salmon fillets', + 'filo pastry', 'almonds', 'milk', 'blue cheese', 'clams', 'shrimp', 'tomato puree', 'chocolate', + 'honey', 'anchovy fillets', 'bulgur', 'prawns', 'parmesan cheese', 'fish', 'shelled large shrimp', + 'gluten', 'crab legs', 'feta cheese', 'whole-milk yogurt', 'crema', 'firm tofu', 'fish stock', + 'fresh ricotta', 'tomato paste', 'fresh cherry tomatoes', 'pork chops', 'eggs', 'greek yogurt', + 'hazelnuts', 'pecans', 'brie cheese', 'oaxaca cheese', 'yellow onion', 'whey', 'silken tofu', + 'toasted bread', 'parmesan', 'beef', 'tofu', 'flour', 'tomatoes', 'red onion', 'slivered almonds', + 'strawberries', 'onions', 'pine nuts', 'cherry tomatoes', 'soy sauce', 'oyster sauce', + 'mozzarella cheese', 'roma tomatoes', 'heavy cream', 'paneer', 'pork tenderloin', 'garlic cloves', + 'swiss cheese', 'grilled king fish', 'ground almonds', 'tilapia', 'sprint onion', 'couscous', + 'walnuts', 'semolina', 'yogurt', 'cotija cheese', 'oysters', 'spaghetti', 'cheddar cheese', + 'butter', 'lobster', 'smoked tofu', 'peanuts', 'ground pork', 'fresh cherry bocconcini', + 'pork belly', 'toasted peanuts', 'roasted peanuts' + } + +ALCOHOLS = {"whiskey", "whisky", "white rum", "dark rum", "bourbon", "rye", "scotch", "vodka", + "tequila", "gin", "dry vermouth", "sweet vermouth", "prosecco","aperol", "brandy", "mezcal", + "triple sec", "coffee liqueur", "almond liqueur", "champagne", "orange curacao", "rum" + } + + +VEGAN_INTERSECTIONS = {'brown sugar', 'carrot', 'sugar', 'vegetable stock', 'fresh ginger', 'nutritional yeast', + 'cayenne pepper', 'olive oil', 'lemon', 'ginger', 'red onion', 'pomegranate molasses', + 'onion', 'water', 'chickpea flour', 'orange zest', 'coconut oil', 'smoked paprika', + 'lemon zest', 'sunflower oil', 'orange juice', 'black pepper', 'cinnamon powder', + 'mushrooms', 'cloves', 'salt', 'oil', 'vegan butter', 'turmeric', 'tomato paste', + 'mustard seeds', 'bell pepper', 'rosemary', 'vinegar', 'tomatoes', 'flour', 'soy sauce', + 'lemon juice', 'garlic'} + +VEGETARIAN_INTERSECTIONS = {'carrot', 'milk', 'basil', 'green lentils', 'vegetable bullion', 'red onions', + 'balsamic vinegar', 'lemon', 'olive oil', 'butter', 'honey', 'red chili', + 'red onion', 'breadcrumbs', 'lemon zest', 'pepitas', 'black pepper', 'fresh peas', + 'salt', 'firm tofu', 'ricotta cheese', 'kosher salt', 'watercress', 'cream', + 'parmesan cheese', 'shallots', 'rosemary', 'sage', 'tomatoes', 'walnuts', + 'lemon juice', 'thyme', 'garlic', 'eggs', 'red wine vinegar'} + +PALEO_INTERSECTIONS = {'basil', 'olive oil', 'honey', 'pine nuts', 'baking soda', 'shrimp', 'cherry tomatoes', + 'coconut oil', 'cinnamon', 'lemon zest', 'cumin', 'black pepper', 'lime', 'salt', + 'zucchini', 'kosher salt', 'chipotle chili', 'eggs', 'coconut flour', 'avocado', + 'cauliflower', 'serrano chili', 'safflower oil', 'tomatoes', 'lemon juice', 'onions', + 'garlic'} + +KETO_INTERSECTIONS = {'fresh cucumber', 'red cabbage', 'olive oil', 'ginger', 'butter', 'dill', 'red onion', + 'monk fruit', 'cherry tomatoes', 'spring onions', 'lime juice', 'fish sauce', + 'sesame seeds', 'black pepper', 'salt', 'chives', 'asparagus', 'eggs', + 'avocado mayonnaise', 'rosemary', 'cauliflower', 'flank steak', 'lemon juice', + 'garlic'} + +OMNIVORE_INTERSECTIONS = {'mint', 'carrot', 'fresh mint', 'olive oil', 'lemon', 'ginger', 'butter', 'honey', + 'leg of lamb', 'red onion', 'bay leaves', 'tamarind concentrate', + 'worcestershire sauce', 'onion', 'lime juice', 'water', 'anchovy fillets', 'celery', + 'black pepper', 'cilantro', 'chili powder', 'salt', 'mayonnaise', 'garlic cloves', + 'kosher salt', 'white onion', 'turmeric', 'rosemary', 'vinegar', 'tomatoes', + 'sea salt', 'soy sauce', 'lemon juice', 'onions', 'thyme', 'garlic', 'avocado', + 'fresh corn tortillas', 'tomato paste'} + + +EXAMPLE_INTERSECTION = {'fresh red chili', 'sugar', 'nutritional yeast', 'fresh ginger', 'red chili powder', 'garlic', + 'olive oil', 'mashed potatoes', 'garam masala', 'clove powder', 'cumin powder', 'onion', + 'chickpea flour', 'water', 'turmeric powder', 'hing', 'black pepper', 'cinnamon powder', + 'cilantro', 'salt', 'oil', 'cardamom powder', 'turmeric', 'garlic paste', 'mustard seeds', + 'vinegar', 'mangoes', 'nigella seeds', 'serrano chili', 'flour', 'soy sauce', 'coriander seeds', + 'coriander powder', 'lemon juice', 'mango powder', 'curry leaves'} + +example_dishes = [ + {'salt', 'breadcrumbs', 'water', 'flour', 'celeriac', 'chickpea flour', 'soy sauce', 'parsley', + 'sunflower oil', 'lemon', 'black pepper'}, + + {'cornstarch', 'salt', 'vegetable oil', 'sugar', 'vegetable stock', 'water', 'tofu', 'soy sauce', + 'lemon zest', 'lemon juice', 'black pepper', 'ginger', 'garlic'}, + + {'salt', 'mixed herbs', 'silken tofu', 'smoked tofu', 'nutritional yeast', 'turmeric', 'soy sauce', + 'garlic', 'lemon juice', 'olive oil', 'black pepper', 'spaghetti'}, + + {'salt', 'mushrooms', 'sugar', 'barley malt', 'nutritional yeast', 'fresh basil', 'olive oil', + 'honey', 'yeast', 'red onion', 'bell pepper', 'cashews', 'oregano', 'rosemary', 'garlic powder', + 'tomatoes', 'water', 'flour', 'red pepper flakes', 'garlic'}, + + {'mango powder', 'oil', 'salt', 'cardamom powder', 'fresh red chili', 'sugar', 'fresh ginger', + 'turmeric', 'red chili powder', 'curry leaves', 'garlic paste', 'mustard seeds', 'vinegar', + 'mashed potatoes', 'garam masala', 'mangoes', 'nigella seeds', 'clove powder', 'serrano chili', + 'cumin powder', 'onion', 'water', 'chickpea flour', 'coriander seeds', 'turmeric powder', 'hing', + 'coriander powder', 'cinnamon powder', 'cilantro', 'garlic'}, + + {'mango powder', 'oil', 'salt', 'cardamom powder', 'fresh red chili', 'sugar', 'fresh ginger', + 'turmeric', 'red chili powder', 'curry leaves', 'garlic paste', 'mustard seeds', 'vinegar', + 'mashed potatoes', 'garam masala', 'mangoes', 'nigella seeds', 'clove powder', 'serrano chili', + 'cumin powder', 'onion', 'water', 'chickpea flour', 'coriander seeds', 'turmeric powder', 'hing', + 'coriander powder', 'cinnamon powder', 'cilantro', 'garlic'} + ] + +one = {'salt', 'breadcrumbs', 'water', 'flour', 'celeriac', 'chickpea flour', + 'soy sauce', 'parsley','sunflower oil', 'lemon', 'black pepper'} + +two = {'cornstarch', 'salt', 'vegetable oil', 'sugar', 'vegetable stock', + 'water', 'tofu', 'soy sauce','lemon zest', 'lemon juice', + 'black pepper','ginger', 'garlic'} + +three = {'salt', 'mixed herbs', 'silken tofu', 'smoked tofu', 'nutritional yeast', + 'turmeric', 'soy sauce','garlic', 'lemon juice', 'olive oil', + 'black pepper','spaghetti'} + +four = {'salt', 'mushrooms', 'sugar', 'barley malt', 'nutritional yeast','fresh basil', + 'olive oil','honey', 'yeast', 'red onion', 'bell pepper','cashews', 'oregano', + 'rosemary', 'garlic powder','tomatoes', 'water','flour', 'red pepper flakes', 'garlic'} + +(one & two | one & three | one & four | two & three | two & four | three & four) \ No newline at end of file diff --git a/exercises/concept/cater-waiter/sets_test.py b/exercises/concept/cater-waiter/sets_test.py new file mode 100644 index 0000000000..9767df33a9 --- /dev/null +++ b/exercises/concept/cater-waiter/sets_test.py @@ -0,0 +1,109 @@ +import unittest +import pytest +from sets_categories import (VEGAN, + VEGETARIAN, + KETO, + PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + +from sets_test_data import (recipes_with_duplicates, + recipes_without_duplicates, + all_drinks, + drink_names, + dishes_categorized, + dishes_to_special_label, + dishes_labeled, + ingredients_only, + dishes_and_appetizers, + dishes_cleaned, + dishes_and_overlap, + singletons) + + +from exemplar import (clean_ingredients, + check_drinks, + categorize_dish, + tag_special_ingredients, + compile_ingredients, + separate_appetizers, + singleton_ingredients,) + + +class SetsTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_clean_ingredients(self): + input_data = recipes_with_duplicates + result_data = recipes_without_duplicates + number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(clean_ingredients(item[0], item[1]), (result[1], result[2])) + + @pytest.mark.task(taskno=2) + def test_check_drinks(self): + input_data = all_drinks + result_data = drink_names + number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(check_drinks(item[0], item[1]), (result)) + + @pytest.mark.task(taskno=3) + def test_categorize_dish(self): + input_data = sorted(recipes_without_duplicates, reverse=True) + result_data = dishes_categorized + number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(categorize_dish(item[1], item[2]), (result)) + + @pytest.mark.task(taskno=4) + def test_tag_special_ingredients(self): + input_data = dishes_to_special_label + result_data = dishes_labeled + number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(tag_special_ingredients(item), (result)) + + @pytest.mark.task(taskno=5) + def test_compile_ingredients(self): + input_data = ingredients_only + result_data = [VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE] + number_of_variants = number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(compile_ingredients(item), (result)) + + @pytest.mark.task(taskno=6) + def test_separate_appetizers(self): + input_data = dishes_and_appetizers + result_data = dishes_cleaned + number_of_variants = number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(sorted(separate_appetizers(item[0], item[1])), (sorted(result))) + + @pytest.mark.task(taskno=7) + def test_singleton_ingredients(self): + input_data = dishes_and_overlap + result_data = singletons + number_of_variants = number_of_variants = range(1, len(input_data) + 1) + + for variant, item, result in zip(number_of_variants, input_data, result_data): + with self.subTest(f"variation #{variant}", item=item, result=result): + self.assertEqual(singleton_ingredients(item[0], item[1]), (result)) diff --git a/exercises/concept/cater-waiter/sets_test_data.py b/exercises/concept/cater-waiter/sets_test_data.py new file mode 100644 index 0000000000..11881ed704 --- /dev/null +++ b/exercises/concept/cater-waiter/sets_test_data.py @@ -0,0 +1,457 @@ +from sets_categories import (VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) + + +################################### +# Data for test_clean_ingredients # +################################### + +recipes_with_duplicates = [('Kisir with Warm Pita', ['bulgur', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'persian cucumber', 'tomato paste', 'spring onion', 'water', 'olive oil', 'bulgur', 'bulgur', 'pomegranate molasses', 'pomegranate molasses', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'tomato', 'persian cucumber', 'tomato paste', 'tomato paste', 'tomato paste']), + ('Shakshuka', ['vegan unsweetened yoghurt', 'yellow onion', 'firm tofu', 'smoked paprika', 'tomatoes', 'tomato paste', 'sugar', 'cloves', 'cumin', "za'atar", 'olive oil', 'harissa', 'red bell pepper']), + ('Vegetarian Khoresh Bademjan', ['yellow split peas', 'tomato paste', 'black pepper', 'pomegranate concentrate', 'yellow onions', 'slivered almonds', 'ground turmeric', 'barberries', 'basmati rice', 'lemon juice', 'hot water', 'cayenne pepper', 'chinese eggplants', 'salt', 'orange juice', 'saffron powder', 'vegan butter', 'orange zest', 'kosher salt', 'yellow split peas', 'yellow split peas', 'tomato paste', 'tomato paste', 'tomato paste', 'black pepper']), + ('Baked Kelewele', ['smoked paprika', 'black peppercorn', 'red onion', 'grains of selim', 'cayenne pepper', 'calabash nutmeg', 'coconut oil', 'cloves', 'fresh ginger', 'salt', 'ripe plantains', 'smoked paprika', 'black peppercorn', 'black peppercorn', 'red onion', 'grains of selim', 'grains of selim', 'grains of selim']), + ('Waakye', ['baking soda', 'sorghum stems', 'coconut oil', 'black-eyed peas', 'water', 'salt', 'white rice', 'baking soda', 'baking soda', 'sorghum stems', 'sorghum stems', 'sorghum stems', 'coconut oil']), + ('Georgian Eggplant Rolls with Walnuts', ['pomegranate seeds', 'oil', 'coriander', 'garlic', 'khmeli suneli', 'eggplants', 'black pepper', 'vinegar', 'walnuts', 'water', 'salt']), + ('Burmese Tofu with Garlic, Ginger and Chili Sauce', ['soy sauce', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'ginger', 'peanuts', 'rice vinegar', 'spring onions', 'water', 'turmeric', 'salt', 'chickpea flour', 'soy sauce', 'soy sauce', 'oil', 'oil', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'brown sugar', 'ginger', 'peanuts', 'peanuts', 'peanuts']), + ('Celeriac Schnitzel', ['soy sauce', 'parsley', 'lemon', 'sunflower oil', 'black pepper', 'celeriac', 'breadcrumbs', 'water', 'salt', 'flour', 'chickpea flour']), + ('Sticky Lemon Tofu', ['soy sauce', 'vegetable stock', 'tofu', 'cornstarch', 'lemon juice', 'lemon zest', 'garlic', 'ginger', 'black pepper', 'sugar', 'water', 'salt', 'vegetable oil', 'soy sauce', 'soy sauce', 'vegetable stock', 'vegetable stock', 'vegetable stock', 'tofu']), + ('Vegan Carbonara', ['soy sauce', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'mixed herbs', 'garlic', 'black pepper', 'silken tofu', 'turmeric', 'salt', 'olive oil', 'spaghetti', 'soy sauce', 'smoked tofu', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'nutritional yeast', 'nutritional yeast']), + ('Vegan Pizza with Caramelized Onions', ['mushrooms', 'rosemary', 'garlic', 'red pepper flakes', 'yeast', 'barley malt', 'water', 'olive oil', 'garlic powder', 'oregano', 'honey', 'nutritional yeast', 'red onion', 'tomatoes', 'cashews', 'sugar', 'bell pepper', 'flour', 'salt', 'fresh basil', 'mushrooms', 'mushrooms', 'rosemary', 'rosemary', 'rosemary', 'garlic']), + ('Cheela with Spicy Mango Chutney', ['clove powder', 'oil', 'cinnamon powder', 'nigella seeds', 'curry leaves', 'coriander seeds', 'garlic', 'mangoes', 'mashed potatoes', 'cardamom powder', 'vinegar', 'water', 'mustard seeds', 'coriander powder', 'cumin powder', 'mango powder', 'garam masala', 'red chili powder', 'hing', 'garlic paste', 'turmeric powder', 'cilantro', 'sugar', 'onion', 'serrano chili', 'fresh ginger', 'turmeric', 'salt', 'fresh red chili', 'chickpea flour']), + ('Sweet and Spicy Crispy Green Beans', ['soy sauce', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'scallions', 'garlic', 'carrot', 'ginger', 'sesame seeds', 'tomato paste', 'bell pepper', 'siracha', 'soy sauce', 'soy sauce', 'pomegranate molasses', 'pomegranate molasses', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'sunflower oil', 'scallions', 'garlic', 'garlic', 'garlic']), + ('Vegan Mini Savory Mince Pies', ['mushrooms', 'cinnamon powder', 'rosemary', 'corn flour', 'ginger', 'brown sugar', 'carrot', 'black pepper', 'raisins', 'butternut squash', 'vegetarian worcestershire sauce', 'parev shortcrust pastry', 'olive oil', 'vegetable stock', 'dried cherries', 'lemon juice', 'lemon zest', 'figs', 'dried cranberries', 'apples', 'pecans', 'onion', 'orange juice', 'currants', 'dried blueberries', 'salt', 'brandy', 'orange zest', 'allspice powder']), + ('Roasted Corn and Zucchini Salad', ['green onions', 'lemon juice', 'lemon zest', 'dill', 'corn', 'tomatoes', 'black pepper', 'zucchini', 'olive oil', 'green onions', 'green onions', 'lemon juice', 'lemon juice', 'lemon juice', 'lemon zest']), + ('Golden Potato Salad', ['mustard seeds', 'cumin seeds', 'lemon juice', 'garlic', 'black pepper', 'balsamic vinegar', 'yukon gold potato', 'chives', 'turmeric', 'salt', 'olive oil', 'mustard seeds', 'cumin seeds', 'cumin seeds', 'lemon juice', 'garlic', 'garlic', 'garlic']), + ('Carrot Puff Pastry Tart', ['olive oil', 'lemon', 'lemon juice', 'pareve puff pastry', 'brown sugar', 'red onion', 'carrot', 'garlic', 'black pepper', 'thyme', 'vegan butter', 'water', 'salt', 'ground almonds', 'olive oil', 'olive oil', 'lemon', 'lemon', 'lemon', 'lemon juice']), + + ('Mushroom Lasagna', ['nutmeg', 'garlic', 'black pepper', 'onions', 'butter', 'parmesan cheese', 'portobello mushrooms', 'flour', 'dried lasagna noodles', 'olive oil', 'milk', 'kosher salt']), + ('Nut Wellington', ['sage', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'thyme', 'marmite', 'breadcrumbs', 'walnuts', 'dates', 'eggs', 'olive oil', 'brazil nuts', 'leeks', 'chestnuts', 'cashews', 'apples', 'pecans', 'butter', 'salt', 'sage', 'sage', 'puff pastry sheets', 'puff pastry sheets', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'black pepper', 'thyme', 'marmite', 'marmite', 'marmite']), + ('White Cheddar Scalloped Potatoes', ['shallots', 'garlic', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'yukon gold potato', 'milk', 'kosher salt']), + ('Winter Cobb Salad', ['smoked tofu', 'shiitake mushrooms', 'red wine vinegar', 'garlic', 'tomatoes', 'black pepper', 'avocados', 'blue cheese', 'onion', 'lacinato kale', 'eggs', 'olive oil', 'smoked tofu', 'smoked tofu', 'shiitake mushrooms', 'shiitake mushrooms', 'shiitake mushrooms', 'red wine vinegar']), + ('Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', ['honey', 'lemon', 'dijon mustard', 'feta cheese', 'red wine vinegar', 'red onion', 'watercress', 'green lentils', 'currants', 'capers', 'pepitas', 'fresh pumpkin', 'olive oil', 'honey', 'lemon', 'lemon', 'dijon mustard', 'feta cheese', 'feta cheese', 'feta cheese']), + ('Cambodian-Style Vegetable Spring Rolls', ['lime juice', 'toasted peanuts', 'firm tofu', 'garlic', 'corn flour', 'bean sprouts', 'carrot', 'palm sugar', 'shallots', 'red chili', 'vermicelli noodles', 'wombok', 'soy sauce', 'sunflower oil', 'spring roll wrappers', 'vegetarian fish sauce', 'lime juice', 'lime juice', 'toasted peanuts', 'toasted peanuts', 'toasted peanuts', 'firm tofu']), + ('Summer Minestrone Cups', ['fresh peas', 'rosemary', 'garlic', 'chickpeas', 'carrot', 'leek', 'green lentils', 'red chili', 'olive oil', 'croutons', 'fresh corn', 'lemon zest', 'green beans', 'parmesan rind', 'basil', 'tomatoes', 'vegetable bullion', 'parmesan cheese', 'celery', 'mint']), + ('Fried Zucchini with Balsamic and Chili Dressing', ['honey', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'mint leaves', 'zucchini', 'olive oil', 'honey', 'honey', 'lemon juice', 'lemon juice', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'balsamic vinegar', 'balsamic vinegar']), + ('Barley Risotto', ['sage', 'beets', 'pearl barley', 'brussel sprouts', 'rosemary', 'garlic', 'carrot', 'red onion', 'black pepper', 'thyme', 'butternut squash', 'vegetable bullion', 'parmesan cheese', 'olive oil', 'white wine']), + ('Cherry Tomato, Watercress and Fava Bean Salad', ['fresh peas', 'fresh cherry tomatoes', 'garlic', 'watercress', 'balsamic vinegar', 'fresh or frozen fava beans', 'fresh cherry bocconcini', 'salt', 'olive oil', 'fresh peas', 'fresh peas', 'fresh cherry tomatoes', 'fresh cherry tomatoes', 'fresh cherry tomatoes', 'garlic']), + ('Fresh Garden Peas over Cauliflower Almond Puree', ['red onions', 'lemon', 'fresh peas', 'garlic', 'grated nutmeg', 'cream', 'cauliflower', 'blanched almonds', 'fresh pea tendrils', 'olive oil', 'vegetable oil', 'red onions', 'lemon', 'lemon', 'fresh peas', 'garlic', 'garlic', 'garlic']), + ('Walnut Ravioli with Artichokes and Tomatoes', ['pine nuts', 'oil marinated artichokes', 'olives', 'rosemary', 'fresh tomatoes', 'ricotta cheese', 'black pepper', 'fresh artichoke hearts', 'walnuts', 'pasta sheets', 'lemon juice', 'lemon zest', 'basil', 'red onion', 'butter', 'salt', 'pine nuts', 'pine nuts', 'oil marinated artichokes', 'oil marinated artichokes', 'oil marinated artichokes', 'olives']), + ('Asparagus Puffs', ['eggs', 'asparagus', 'lemon juice', 'red onion', 'ricotta cheese', 'black pepper', 'thyme', 'salt', 'parmesan cheese', 'puff pastry', 'chives']), + ('Grilled Tofu Tacos', ['cotija cheese', 'masa', 'fresh cilantro leaves', 'jalapeΓ±o chili', 'chipotle chili', 'firm tofu', 'garlic', 'carrot', 'roasted corn', 'tomatillos', 'pepitas', 'ancho chili', 'crema', 'red onions', 'pasilla chili', 'lemon', 'hot water', 'lemon juice', 'tomatoes', 'avocado', 'cumin', 'red cabbage', 'limes', 'black beans', 'cotija cheese', 'cotija cheese', 'masa', 'masa', 'masa', 'fresh cilantro leaves', 'jalapeΓ±o chili', 'chipotle chili', 'chipotle chili', 'firm tofu', 'garlic', 'garlic', 'garlic']), + + ('Zucchini Fritters with Lemon-Thyme Coconut Yogurt', ['baking soda', 'coconut flour', 'lemon juice', 'lemon zest', 'eggs', 'coconut yogurt', 'black pepper', 'fresh thai chili', 'coconut oil', 'chives', 'zucchini', 'salt']), + ('Avocado Deviled Eggs', ['lime juice', 'fresh cilantro leaves', 'eggs', 'seranno chili', 'avocado', 'pepitas', 'salt', 'garlic powder', 'lime juice', 'lime juice', 'fresh cilantro leaves', 'fresh cilantro leaves', 'fresh cilantro leaves', 'eggs']), + ('Grilled Flank Steak with Caesar Salad', ['pine nuts', 'white vinegar', 'chipotle chili', 'scallions', 'garlic', 'paleo parmesan cheese', 'black pepper', 'avocado oil', 'treviso', 'olive oil', 'radishes', 'flank steak', 'dijon mustard', 'castelfranco radicchio', 'worcestershire sauce', 'fresh parsley', 'cherry tomatoes', 'salt', 'avocado mayonnaise', 'pine nuts', 'white vinegar', 'white vinegar', 'chipotle chili', 'scallions', 'scallions', 'scallions']), + ('Pumpkin Bread Crostini', ['coconut flour', 'garlic', 'black pepper', 'cloves', 'eggs', 'olive oil', 'onions', 'honey', 'apple cider vinegar', 'almond butter', 'baking soda', 'nutmeg', 'pumpkin puree', 'cinnamon', 'shrimp', 'basil', 'coconut oil', 'cherry tomatoes', 'salt', 'fresh red chili', 'coconut flour', 'coconut flour', 'garlic', 'garlic', 'garlic', 'black pepper']), + ('BLT Bites', ['mustard seed', 'onion', 'kale', 'cherry tomatoes', 'bacon', 'paleo mayonnaise']), + ('Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', ['purple sweet potato', 'chiles de Γ‘rbol', 'garlic', 'tomatoes', 'safflower oil', 'black pepper', 'mexican oregano', 'avocados', 'shallots', 'cumin', 'olive oil', 'lemons', 'whole chicken', 'limes', 'kosher salt', 'purple sweet potato', 'purple sweet potato', 'chiles de Γ‘rbol', 'chiles de Γ‘rbol', 'chiles de Γ‘rbol', 'garlic', 'tomatoes', 'safflower oil', 'safflower oil', 'black pepper', 'mexican oregano', 'mexican oregano', 'mexican oregano']), + ('Chicken with Tamarind and Apricot Sauce', ['garlic', 'black pepper', 'dried apricots', 'roma tomatoes', 'water', 'olive oil', 'honey', 'cinnamon', 'ground cumin', 'cider vinegar', 'chili powder', 'safflower oil', 'homemade tamarind concentrate', 'white chicken', 'allspice', 'chipotles', 'salt', 'homemade apricot honey preserves', 'kosher salt']), + ('Grilled Fish Tacos with Cauliflower Tortillas', ['green onions', 'serrano chili', 'shredded red cabbage', 'smoked paprika', 'mango', 'eggs', 'black pepper', 'cilantro', 'cauliflower', 'avocado', 'lime', 'cumin', 'salt', 'tilapia', 'green onions', 'green onions', 'serrano chili', 'serrano chili', 'serrano chili', 'shredded red cabbage']), + ('Grilled Pork Chops with Mango Pineapple Salsa', ['cilantro leaves', 'lime', 'pineapple', 'chipotle chili', 'garlic', 'mangoes', 'cauliflower', 'avocado', 'serrano chili', 'pork chops', 'lime zest', 'lacinato kale', 'onions', 'cilantro leaves', 'lime', 'lime', 'pineapple', 'chipotle chili', 'chipotle chili', 'chipotle chili']), + ('Grilled Shrimp and Pesto over Zucchini Noodles', ['pine nuts', 'shrimp', 'green bell pepper', 'lemon juice', 'basil', 'lemon zest', 'garlic', 'tomatoes', 'cashews', 'yellow bell pepper', 'cumin', 'zucchini', 'salt', 'olive oil', 'red bell pepper', 'pine nuts', 'pine nuts', 'shrimp', 'shrimp', 'shrimp', 'green bell pepper']), + + ('Cauliflower Pizza with Roasted Tomatoes and Chicken', ['parmesan', 'almond meal', 'rosemary', 'mozzarella cheese', 'roasted chicken', 'tomato paste', 'cauliflower', 'cherry tomatoes', 'eggs', 'fresh basil', 'olive oil']), + ('Flank Steak with Chimichurri and Asparagus', ['white vinegar', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'garlic', 'black pepper', 'cauliflower', 'sour cream', 'fresh parsley', 'salt', 'olive oil', 'white vinegar', 'white vinegar', 'asparagus', 'asparagus', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'scallions', 'garlic', 'black pepper', 'black pepper', 'black pepper']), + ('Kingfish Lettuce Cups', ['soy sauce', 'watermelon radishes', 'lime juice', 'fish sauce', 'mirin', 'little gem lettuce heads', 'peanut oil', 'garlic', 'sesame seeds', 'oyster sauce', 'spring onions', 'avocado', 'grilled king fish', 'red cabbage']), + ('Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', ['clove powder', 'curry leaves', 'coriander seeds', 'ginger', 'cardamom powder', 'vinegar', 'mustard seeds', 'mango powder', 'garam masala', 'red chili powder', 'chicken', 'hing', 'turmeric powder', 'tomatoes', 'ginger garlic paste', 'fresh greek yogurt', 'fresh ginger', 'monk fruit', 'turmeric', 'cashew nuts', 'salt', 'fresh red chili', 'cinnamon powder', 'nigella seeds', 'whole small crimini mushrooms', 'brussel sprouts', 'garlic', 'mangoes', 'heavy cream', 'cloves', 'coriander powder', 'cumin powder', 'cardamom', 'green chili', 'cinnamon', 'garlic paste', 'red chili flakes', 'lemon juice', 'cilantro', 'butter', 'dried fenugreek leaves', 'boned chicken', 'clove powder', 'clove powder', 'curry leaves', 'curry leaves', 'curry leaves', 'coriander seeds']), + ('Prawn and Herb Omelette', ['green onions', 'parsley', 'sesame seeds', 'black pepper', 'chives', 'eggs', 'fennel bulb', 'tahini', 'olive oil', 'harissa', 'shrimp', 'lemon juice', 'dill', 'butter', 'onion', 'fresh cucumber', 'monk fruit', 'salt', 'green onions', 'parsley', 'parsley', 'sesame seeds', 'black pepper', 'black pepper', 'black pepper']), + ('Satay Steak Skewers', ['sriacha', 'apple cider vinegar', 'lime juice', 'fish sauce', 'red and green thai chili', 'flank steak', 'carrot', 'peanuts', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'kecap manis', 'monk fruit', 'micro cilantro', 'olive oil', 'sriacha', 'sriacha', 'apple cider vinegar', 'apple cider vinegar', 'apple cider vinegar', 'lime juice']), + ('Parmesan Crackers and Spinach Crackers with Salmon Pate', ['spinach', 'parmesan cheese', 'coconut flour', 'chili flakes', 'garlic', 'black pepper', 'cream cheese', 'ghee', 'lemon juice', 'flaxmeal', 'red onion', 'salt', 'salmon fillets', 'pecans', 'almond flour', 'cumin', 'fresh cucumber', 'cherry tomatoes', 'chives', 'avocado mayonnaise']), + ('Pork Chops with Grilled Castelfranco Radicchio and Asparagus', ['rosemary', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'eggs', 'oregano', 'asparagus', 'lemon', 'dijon mustard', 'basil', 'castelfranco radicchio', 'dill', 'butter', 'pork chops', 'monk fruit', 'salt', 'avocado mayonnaise', 'rosemary', 'rosemary', 'garlic', 'garlic', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'avocado oil', 'eggs', 'oregano', 'oregano', 'oregano']), + ('Seared Salmon with Pickled Vegetable and Watercress Salad', ['lime juice', 'caster sugar', 'toasted buckwheat', 'lemon juice', 'red wine vinegar', 'red onion', 'dutch carrot', 'salmon steaks', 'watercress', 'pink peppercorns', 'shallots', 'fennel seeds', 'red cabbage', 'radishes']), + ('Braised Pork Belly with Apple Salad', ['cilantro leaves', 'green cabbage', 'lemon juice', 'pork belly', 'dark soy sauce', 'granny smith apples', 'ginger', 'light soy sauce', 'sesame seeds', 'black pepper', 'cinnamon sticks', 'spring onions', 'star anise', 'monk fruit', 'olive oil', 'cilantro leaves', 'cilantro leaves', 'green cabbage', 'green cabbage', 'green cabbage', 'lemon juice']), + + ('Beachside Snapper', ['lime juice', 'salsa', 'green bell pepper', 'anaheim chili', 'black pepper', 'olive oil', 'yellow mustard', 'red bell pepper', 'soy sauce', 'mexican crema', 'mayonnaise', 'white onion', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'tomatoes', 'limes', 'worcestershire sauce', 'butter', 'yellow bell pepper', 'salt', 'red snapper', 'lime juice', 'salsa', 'salsa', 'green bell pepper', 'anaheim chili', 'anaheim chili', 'anaheim chili']), + ('Governor Shrimp Tacos', ['lime juice', 'poblano chili', 'tomato paste', 'black pepper', 'chipotle adobo sauce', 'chile manzano', 'roma tomatoes', 'pepitas', 'oaxaca cheese', 'white onion', 'shelled large shrimp', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'worcestershire sauce', 'avocado', 'butter', 'kosher salt', 'lime juice', 'lime juice', 'poblano chili', 'poblano chili', 'poblano chili', 'tomato paste']), + ('Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', ['fresh tortillas', 'shrimp', 'garlic', 'chickpeas', 'black pepper', 'slivered almonds', 'guajillo chile', 'bacon', 'sea salt', 'butter', 'onion', 'avocado', 'olive oil']), + ('Burnt Masala Wings with Classic Coleslaw', ['lime juice', 'green cabbage', 'chiles de Γ‘rbol', 'green cardamom', 'ginger', 'carrot', 'sriracha', 'black pepper', 'cinnamon sticks', 'celery seeds', 'cloves', 'black cardamom', 'olive oil', 'chicken wings', 'apple cider vinegar', 'mayonnaise', 'honey', 'black peppercorns', 'lemon juice', 'garlic cloves', 'tamarind concentrate', 'cilantro', 'butter', 'serrano chili', 'red cabbage', 'kosher salt', 'lime juice', 'lime juice', 'green cabbage', 'green cabbage', 'green cabbage', 'chiles de Γ‘rbol', 'green cardamom', 'ginger', 'ginger', 'carrot', 'sriracha', 'sriracha', 'sriracha']), + ('Dahi Puri with Black Chickpeas', ['whole-milk yogurt', 'chaat masala', 'ginger', 'pani puri', 'scallion chutney', 'yukon gold potato', 'black chickpeas', 'thin sev', 'date syrup', 'red onion', 'roasted chicken', 'chili powder', 'tamarind concentrate', 'cumin', 'turmeric', 'mint']), + ('Brisket with Grilled Rhubarb, Onions, and Fennel', ['white vinegar', 'parsley', 'yellow onion', 'rhubarb', 'garlic', 'brown sugar', 'black pepper', 'thyme', 'crushed red pepper flakes', 'fennel bulbs', 'beer', 'marjoram', 'vegetable oil', 'soy sauce', 'oregano', 'lemon', 'red onion', 'chili powder', 'cilantro', 'beef brisket', 'balsamic vinegar', 'worcestershire sauce', 'celery', 'mint', 'kosher salt', 'white vinegar', 'white vinegar', 'parsley', 'parsley', 'parsley', 'yellow onion']), + ('Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', ['oranges', 'rosemary', 'garlic', 'anchovy fillets', 'couscous', 'carrot', 'sesame seeds', 'fresh thyme', 'vinegar', 'olive oil', 'tahini', 'harissa', 'onions', 'honey', 'fresh mint', 'leg of lamb', 'tomatoes', 'baby carrot', 'vegetable bullion', 'filo pastry', 'celery', 'bay leaves', 'yoghurt', 'oranges', 'rosemary', 'rosemary', 'garlic', 'anchovy fillets', 'anchovy fillets', 'anchovy fillets']), + ('Baked Chicken Jollof Rice', ['tomato puree', 'garlic', 'ginger', 'tomato', 'carrot', 'thyme', 'white pepper', 'water', 'maggi cubes', 'chicken', 'rice', 'coriander', 'scotch bonnet pepper', 'bell pepper', 'onion', 'turmeric', 'salt', 'tomato puree', 'tomato puree', 'garlic', 'garlic', 'garlic', 'ginger']), + ('Seafood Risotto', ['garlic', 'tomato paste', 'baby scallops', 'mussels', 'water', 'crab legs', 'olive oil', 'baby squid', 'fish stock', 'lemon juice', 'white onion', 'arborio risotto rice', 'clams', 'parmesan cheese', 'flat-leaf parsley', 'cherry tomatoes', 'prawns', 'white wine']), + ('Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', ['toasted bread', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'carrot', 'summer squash', 'black pepper', 'red pepper flakes', 'vinegar', 'sea salt', 'zucchini', 'olive oil', 'onions', 'white wine vinegar', 'fresh mint', 'leg of lamb', 'lemon', 'fresh ricotta', 'sugar', 'celery', 'bay leaves', 'kosher salt', 'toasted bread', 'toasted bread', 'rosemary', 'rosemary', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'garlic', 'carrot', 'summer squash', 'summer squash', 'summer squash']) + ] + +recipes_without_duplicates = [('kisir_with_warm_pita', 'Kisir with Warm Pita', {'water', 'chopped parsley', 'pomegranate molasses', 'spring onion', 'lemon juice', 'olive oil', 'bulgur', 'tomato paste', 'tomato', 'persian cucumber'}), + ('shakshuka', 'Shakshuka', {'smoked paprika', 'tomatoes', 'cumin', 'firm tofu', 'olive oil', 'harissa', 'yellow onion', 'sugar', "za'atar", 'tomato paste', 'cloves', 'red bell pepper', 'vegan unsweetened yoghurt'}), + ('vegetarian_khoresh_bademjan', 'Vegetarian Khoresh Bademjan', {'pomegranate concentrate', 'saffron powder', 'cayenne pepper', 'barberries', 'salt', 'yellow onions', 'yellow split peas', 'slivered almonds', 'ground turmeric', 'orange zest', 'lemon juice', 'kosher salt', 'hot water', 'basmati rice', 'black pepper', 'orange juice', 'tomato paste', 'vegan butter', 'chinese eggplants'}), + ('baked_kelewele', 'Baked Kelewele', {'salt', 'coconut oil', 'smoked paprika', 'cayenne pepper', 'red onion', 'fresh ginger', 'calabash nutmeg', 'grains of selim', 'black peppercorn', 'cloves', 'ripe plantains'}), + ('waakye', 'Waakye', {'salt', 'coconut oil', 'water', 'white rice', 'sorghum stems', 'black-eyed peas', 'baking soda'}), + ('georgian_eggplant_rolls_with_walnuts', 'Georgian Eggplant Rolls with Walnuts', {'salt', 'coriander', 'pomegranate seeds', 'oil', 'water', 'vinegar', 'garlic', 'eggplants', 'black pepper', 'khmeli suneli', 'walnuts'}), + ('burmese_tofu_with_garlic,_ginger_and_chili_sauce', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', {'salt', 'rice vinegar', 'oil', 'water', 'turmeric', 'chili flakes', 'spring onions', 'brown sugar', 'garlic', 'chickpea flour', 'ginger', 'soy sauce', 'peanuts'}), + ('celeriac_schnitzel', 'Celeriac Schnitzel', {'salt', 'parsley', 'water', 'sunflower oil', 'flour', 'breadcrumbs', 'lemon', 'celeriac', 'chickpea flour', 'soy sauce', 'black pepper'}), + ('sticky_lemon_tofu', 'Sticky Lemon Tofu', {'salt', 'water', 'tofu', 'cornstarch', 'vegetable stock', 'vegetable oil', 'lemon juice', 'garlic', 'black pepper', 'ginger', 'soy sauce', 'sugar', 'lemon zest'}), + ('vegan_carbonara', 'Vegan Carbonara', {'salt', 'turmeric', 'spaghetti', 'lemon juice', 'olive oil', 'garlic', 'black pepper', 'nutritional yeast', 'soy sauce', 'smoked tofu', 'silken tofu', 'mixed herbs'}), + ('vegan_pizza_with_caramelized_onions', 'Vegan Pizza with Caramelized Onions', {'red pepper flakes', 'garlic', 'cashews', 'fresh basil', 'flour', 'tomatoes', 'red onion', 'oregano', 'nutritional yeast', 'rosemary', 'water', 'bell pepper', 'honey', 'barley malt', 'olive oil', 'salt', 'garlic powder', 'mushrooms', 'yeast', 'sugar'}), + ('cheela_with_spicy_mango_chutney', 'Cheela with Spicy Mango Chutney', {'hing', 'curry leaves', 'mangoes', 'garlic', 'nigella seeds', 'garlic paste', 'coriander seeds', 'oil', 'turmeric', 'red chili powder', 'coriander powder', 'cardamom powder', 'turmeric powder', 'clove powder', 'water', 'cumin powder', 'fresh ginger', 'vinegar', 'cinnamon powder', 'cilantro', 'chickpea flour', 'onion', 'salt', 'mango powder', 'fresh red chili', 'mashed potatoes', 'mustard seeds', 'serrano chili', 'garam masala', 'sugar'}), + ('sweet_and_spicy_crispy_green_beans', 'Sweet and Spicy Crispy Green Beans', {'sesame oil', 'siracha', 'sunflower oil', 'pomegranate molasses', 'sesame seeds', 'green beans', 'carrot', 'scallions', 'garlic', 'ginger', 'soy sauce', 'tomato paste', 'bell pepper'}), + ('vegan_mini_savory_mince_pies', 'Vegan Mini Savory Mince Pies', {'apples', 'brandy', 'pecans', 'raisins', 'brown sugar', 'lemon zest', 'dried blueberries', 'vegetarian worcestershire sauce', 'orange zest', 'butternut squash', 'corn flour', 'rosemary', 'vegetable stock', 'carrot', 'figs', 'cinnamon powder', 'olive oil', 'orange juice', 'black pepper', 'onion', 'dried cherries', 'salt', 'dried cranberries', 'parev shortcrust pastry', 'mushrooms', 'allspice powder', 'lemon juice', 'ginger', 'currants'}), + ('roasted_corn_and_zucchini_salad', 'Roasted Corn and Zucchini Salad', {'zucchini', 'tomatoes', 'green onions', 'corn', 'lemon juice', 'olive oil', 'black pepper', 'lemon zest', 'dill'}), + ('golden_potato_salad', 'Golden Potato Salad', {'salt', 'yukon gold potato', 'turmeric', 'balsamic vinegar', 'cumin seeds', 'lemon juice', 'olive oil', 'garlic', 'mustard seeds', 'black pepper', 'chives'}), + ('carrot_puff_pastry_tart', 'Carrot Puff Pastry Tart', {'salt', 'water', 'lemon', 'thyme', 'red onion', 'carrot', 'lemon juice', 'pareve puff pastry', 'ground almonds', 'brown sugar', 'olive oil', 'garlic', 'black pepper', 'vegan butter'}), + + ('mushroom_lasagna', 'Mushroom Lasagna', {'dried lasagna noodles', 'portobello mushrooms', 'nutmeg', 'flour', 'kosher salt', 'milk', 'olive oil', 'garlic', 'onions', 'butter', 'black pepper', 'parmesan cheese'}), + ('nut_wellington', 'Nut Wellington', {'apples', 'eggs', 'hazelnuts', 'pecans', 'thyme', 'dates', 'cashews', 'breadcrumbs', 'almonds', 'marmite', 'sage', 'leeks', 'olive oil', 'black pepper', 'walnuts', 'salt', 'chestnuts', 'brazil nuts', 'butter', 'puff pastry sheets'}), + ('white_cheddar_scalloped_potatoes', 'White Cheddar Scalloped Potatoes', {'yukon gold potato', 'shallots', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'kosher salt', 'milk', 'garlic'}), + ('winter_cobb_salad', 'Winter Cobb Salad', {'lacinato kale', 'eggs', 'red wine vinegar', 'shiitake mushrooms', 'tomatoes', 'avocados', 'olive oil', 'blue cheese', 'garlic', 'black pepper', 'onion', 'smoked tofu'}), + ('roast_pumpkin_and_lentil_salad_with_roasted_lemon_dressing', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', {'red wine vinegar', 'dijon mustard', 'lemon', 'honey', 'red onion', 'feta cheese', 'olive oil', 'capers', 'pepitas', 'fresh pumpkin', 'watercress', 'green lentils', 'currants'}), + ('cambodian-style_vegetable_spring_rolls', 'Cambodian-Style Vegetable Spring Rolls', {'sunflower oil', 'vegetarian fish sauce', 'shallots', 'vermicelli noodles', 'wombok', 'firm tofu', 'lime juice', 'corn flour', 'palm sugar', 'bean sprouts', 'spring roll wrappers', 'garlic', 'red chili', 'soy sauce', 'toasted peanuts', 'carrot'}), + ('summer_minestrone_cups', 'Summer Minestrone Cups', {'leek', 'garlic', 'lemon zest', 'tomatoes', 'red chili', 'chickpeas', 'rosemary', 'carrot', 'vegetable bullion', 'fresh corn', 'fresh peas', 'green beans', 'olive oil', 'parmesan cheese', 'croutons', 'celery', 'mint', 'basil', 'green lentils', 'parmesan rind'}), + ('fried_zucchini_with_balsamic_and_chili_dressing', 'Fried Zucchini with Balsamic and Chili Dressing', {'zucchini', 'balsamic vinegar', 'honey', 'red onion', 'lemon juice', 'olive oil', 'mint leaves', 'garlic', 'red thai chili', 'pomegranate'}), + ('barley_risotto', 'Barley Risotto', {'beets', 'white wine', 'thyme', 'red onion', 'carrot', 'butternut squash', 'olive oil', 'sage', 'garlic', 'brussel sprouts', 'rosemary', 'black pepper', 'parmesan cheese', 'pearl barley', 'vegetable bullion'}), + ('cherry_tomato,_watercress_and_fava_bean_salad', 'Cherry Tomato, Watercress and Fava Bean Salad', {'salt', 'fresh or frozen fava beans', 'fresh peas', 'balsamic vinegar', 'olive oil', 'garlic', 'watercress', 'fresh cherry bocconcini', 'fresh cherry tomatoes'}), + ('fresh_garden_peas_over_cauliflower_almond_puree', 'Fresh Garden Peas over Cauliflower Almond Puree', {'grated nutmeg', 'red onions', 'lemon', 'fresh peas', 'cream', 'vegetable oil', 'olive oil', 'garlic', 'blanched almonds', 'cauliflower', 'fresh pea tendrils'}), + ('walnut_ravioli_with_artichokes_and_tomatoes', 'Walnut Ravioli with Artichokes and Tomatoes', {'salt', 'fresh tomatoes', 'ricotta cheese', 'lemon zest', 'olives', 'red onion', 'lemon juice', 'black pepper', 'rosemary', 'butter', 'basil', 'fresh artichoke hearts', 'pasta sheets', 'pine nuts', 'walnuts', 'oil marinated artichokes'}), + ('asparagus_puffs', 'Asparagus Puffs', {'salt', 'asparagus', 'ricotta cheese', 'thyme', 'puff pastry', 'red onion', 'eggs', 'lemon juice', 'black pepper', 'parmesan cheese', 'chives'}), + ('grilled_tofu_tacos', 'Grilled Tofu Tacos', {'carrot', 'red cabbage', 'ancho chili', 'limes', 'hot water', 'garlic', 'roasted corn', 'masa', 'pasilla chili', 'lemon', 'tomatoes', 'cumin', 'fresh cilantro leaves', 'chipotle chili', 'red onions', 'pepitas', 'tomatillos', 'black beans', 'cotija cheese', 'crema', 'firm tofu', 'lemon juice', 'jalapeΓ±o chili', 'avocado'}), + + ('zucchini_fritters_with_lemon-thyme_coconut_yogurt', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', {'salt', 'coconut oil', 'eggs', 'fresh thai chili', 'coconut yogurt', 'zucchini', 'lemon juice', 'black pepper', 'coconut flour', 'chives', 'lemon zest', 'baking soda'}), + ('avocado_deviled_eggs', 'Avocado Deviled Eggs', {'salt', 'eggs', 'garlic powder', 'seranno chili', 'avocado', 'lime juice', 'pepitas', 'fresh cilantro leaves'}), + ('grilled_flank_steak_with_caesar_salad', 'Grilled Flank Steak with Caesar Salad', {'flank steak', 'avocado oil', 'treviso', 'scallions', 'garlic', 'cherry tomatoes', 'pine nuts', 'white vinegar', 'chipotle chili', 'dijon mustard', 'olive oil', 'avocado mayonnaise', 'black pepper', 'paleo parmesan cheese', 'castelfranco radicchio', 'fresh parsley', 'salt', 'worcestershire sauce', 'radishes'}), + ('pumpkin_bread_crostini', 'Pumpkin Bread Crostini', {'eggs', 'nutmeg', 'cinnamon', 'garlic', 'pumpkin puree', 'apple cider vinegar', 'cherry tomatoes', 'onions', 'coconut flour', 'cloves', 'shrimp', 'coconut oil', 'honey', 'olive oil', 'black pepper', 'almond butter', 'salt', 'fresh red chili', 'basil', 'baking soda'}), + ('blt_bites', 'BLT Bites', {'paleo mayonnaise', 'bacon', 'kale', 'cherry tomatoes', 'mustard seed', 'onion'}), + ('roasted_chicken_with_roasted_tomatoes,_avocado,_and_sweet_potatoes', 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', {'safflower oil', 'shallots', 'whole chicken', 'lemons', 'tomatoes', 'purple sweet potato', 'avocados', 'limes', 'kosher salt', 'olive oil', 'mexican oregano', 'garlic', 'black pepper', 'cumin', 'chiles de Γ‘rbol'}), + ('chicken_with_tamarind_and_apricot_sauce', 'Chicken with Tamarind and Apricot Sauce', {'cinnamon', 'garlic', 'cider vinegar', 'chipotles', 'homemade tamarind concentrate', 'roma tomatoes', 'white chicken', 'ground cumin', 'water', 'safflower oil', 'allspice', 'dried apricots', 'honey', 'olive oil', 'black pepper', 'salt', 'homemade apricot honey preserves', 'kosher salt', 'chili powder'}), + ('grilled_fish_tacos_with_cauliflower_tortillas', 'Grilled Fish Tacos with Cauliflower Tortillas', {'salt', 'eggs', 'smoked paprika', 'shredded red cabbage', 'mango', 'green onions', 'lime', 'cumin', 'tilapia', 'cilantro', 'black pepper', 'serrano chili', 'cauliflower', 'avocado'}), + ('grilled_pork_chops_with_mango_pineapple_salsa', 'Grilled Pork Chops with Mango Pineapple Salsa', {'pork chops', 'lacinato kale', 'chipotle chili', 'serrano chili', 'lime zest', 'pineapple', 'lime', 'garlic', 'onions', 'mangoes', 'cauliflower', 'avocado', 'cilantro leaves'}), + ('grilled_shrimp_and_pesto_over_zucchini_noodles', 'Grilled Shrimp and Pesto over Zucchini Noodles', {'salt', 'green bell pepper', 'cashews', 'zucchini', 'tomatoes', 'red bell pepper', 'cumin', 'lemon juice', 'yellow bell pepper', 'olive oil', 'garlic', 'pine nuts', 'basil', 'lemon zest', 'shrimp'}), + + ('cauliflower_pizza_with_roasted_tomatoes_and_chicken', 'Cauliflower Pizza with Roasted Tomatoes and Chicken', {'roasted chicken', 'eggs', 'fresh basil', 'olive oil', 'almond meal', 'cherry tomatoes', 'rosemary', 'cauliflower', 'mozzarella cheese', 'tomato paste', 'parmesan'}), + ('flank_steak_with_chimichurri_and_asparagus', 'Flank Steak with Chimichurri and Asparagus', {'fresh parsley', 'salt', 'asparagus', 'chipotle chili', 'flank steak', 'scallions', 'olive oil', 'garlic', 'black pepper', 'cauliflower', 'white vinegar', 'sour cream'}), + ('kingfish_lettuce_cups', 'Kingfish Lettuce Cups', {'oyster sauce', 'fish sauce', 'spring onions', 'sesame seeds', 'grilled king fish', 'little gem lettuce heads', 'mirin', 'red cabbage', 'lime juice', 'peanut oil', 'garlic', 'watermelon radishes', 'soy sauce', 'avocado'}), + ('butter_chicken_with_grilled_mushrooms,_brussel_sprouts_and_mango_chutney', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', {'hing', 'curry leaves', 'cashew nuts', 'green chili', 'cinnamon', 'mangoes', 'garlic', 'nigella seeds', 'garlic paste', 'coriander seeds', 'turmeric', 'ginger garlic paste', 'tomatoes', 'red chili powder', 'coriander powder', 'cardamom powder', 'turmeric powder', 'clove powder', 'cloves', 'heavy cream', 'cardamom', 'fresh greek yogurt', 'monk fruit', 'fresh ginger', 'cumin powder', 'vinegar', 'cinnamon powder', 'cilantro', 'brussel sprouts', 'whole small crimini mushrooms', 'salt', 'boned chicken', 'red chili flakes', 'mango powder', 'fresh red chili', 'lemon juice', 'garam masala', 'butter', 'ginger', 'mustard seeds', 'chicken', 'dried fenugreek leaves'}), + ('prawn_and_herb_omelette', 'Prawn and Herb Omelette', {'salt', 'parsley', 'eggs', 'fresh cucumber', 'sesame seeds', 'green onions', 'monk fruit', 'lemon juice', 'olive oil', 'tahini', 'harissa', 'black pepper', 'butter', 'onion', 'fennel bulb', 'chives', 'shrimp', 'dill'}), + ('satay_steak_skewers', 'Satay Steak Skewers', {'flank steak', 'red and green thai chili', 'kecap manis', 'fish sauce', 'monk fruit', 'micro cilantro', 'carrot', 'apple cider vinegar', 'sriacha', 'lime juice', 'olive oil', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'peanuts'}), + ('parmesan_crackers_and_spinach_crackers_with_salmon_pate', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', {'fresh cucumber', 'pecans', 'ghee', 'garlic', 'chives', 'flaxmeal', 'chili flakes', 'almond flour', 'salmon fillets', 'red onion', 'cherry tomatoes', 'coconut flour', 'cumin', 'spinach', 'cream cheese', 'avocado mayonnaise', 'black pepper', 'parmesan cheese', 'salt', 'lemon juice'}), + ('pork_chops_with_grilled_castelfranco_radicchio_and_asparagus', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', {'pork chops', 'salt', 'asparagus', 'eggs', 'dijon mustard', 'avocado oil', 'lemon', 'thyme', 'monk fruit', 'oregano', 'avocado mayonnaise', 'garlic', 'black pepper', 'rosemary', 'butter', 'basil', 'castelfranco radicchio', 'dill'}), + ('seared_salmon_with_pickled_vegetable_and_watercress_salad', 'Seared Salmon with Pickled Vegetable and Watercress Salad', {'red wine vinegar', 'caster sugar', 'salmon steaks', 'radishes', 'shallots', 'red onion', 'pink peppercorns', 'toasted buckwheat', 'lemon juice', 'lime juice', 'red cabbage', 'watercress', 'fennel seeds', 'dutch carrot'}), + ('braised_pork_belly_with_apple_salad', 'Braised Pork Belly with Apple Salad', {'spring onions', 'dark soy sauce', 'light soy sauce', 'pork belly', 'monk fruit', 'green cabbage', 'star anise', 'sesame seeds', 'lemon juice', 'olive oil', 'black pepper', 'ginger', 'cinnamon sticks', 'granny smith apples', 'cilantro leaves'}), + + ('beachside_snapper', 'Beachside Snapper', {'yellow mustard', 'mayonnaise', 'limes', 'white onion', 'red snapper', 'fresh corn tortillas', 'tomatoes', 'red onion', 'lime juice', 'soy sauce', 'mexican crema', 'salsa', 'garlic cloves', 'green bell pepper', 'olive oil', 'black pepper', 'salt', 'yellow bell pepper', 'worcestershire sauce', 'anaheim chili', 'butter', 'red bell pepper'}), + ('governor_shrimp_tacos', 'Governor Shrimp Tacos', {'chile manzano', 'worcestershire sauce', 'oaxaca cheese', 'garlic cloves', 'red onion', 'avocado', 'lime juice', 'kosher salt', 'white onion', 'chipotle adobo sauce', 'poblano chili', 'fresh corn tortillas', 'butter', 'black pepper', 'pepitas', 'tomato paste', 'roma tomatoes', 'shelled large shrimp'}), + ('shrimp,_bacon_and_crispy_chickpea_tacos_with_salsa_de_guacamole', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'fresh tortillas', 'slivered almonds', 'bacon', 'sea salt', 'chickpeas', 'olive oil', 'guajillo chile', 'garlic', 'butter', 'black pepper', 'onion', 'shrimp', 'avocado'}), + ('burnt_masala_wings_with_classic_coleslaw', 'Burnt Masala Wings with Classic Coleslaw', {'mayonnaise', 'carrot', 'red cabbage', 'green cabbage', 'apple cider vinegar', 'lime juice', 'cloves', 'cinnamon sticks', 'sriracha', 'celery seeds', 'chicken wings', 'garlic cloves', 'honey', 'olive oil', 'cilantro', 'black pepper', 'chiles de Γ‘rbol', 'tamarind concentrate', 'green cardamom', 'black cardamom', 'lemon juice', 'kosher salt', 'serrano chili', 'ginger', 'black peppercorns', 'butter'}), + ('dahi_puri_with_black_chickpeas', 'Dahi Puri with Black Chickpeas', {'roasted chicken', 'scallion chutney', 'yukon gold potato', 'turmeric', 'black chickpeas', 'whole-milk yogurt', 'chili powder', 'red onion', 'pani puri', 'ginger', 'mint', 'thin sev', 'date syrup', 'cumin', 'chaat masala', 'tamarind concentrate'}), + ('brisket_with_grilled_rhubarb,_onions,_and_fennel', 'Brisket with Grilled Rhubarb, Onions, and Fennel', {'crushed red pepper flakes', 'rhubarb', 'thyme', 'yellow onion', 'garlic', 'brown sugar', 'beer', 'lemon', 'red onion', 'oregano', 'soy sauce', 'white vinegar', 'beef brisket', 'parsley', 'marjoram', 'balsamic vinegar', 'vegetable oil', 'fennel bulbs', 'cilantro', 'black pepper', 'worcestershire sauce', 'celery', 'kosher salt', 'mint', 'chili powder'}), + ('roast_leg_of_lamb_with_crispy_moroccan_carrots_&_couscous', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', {'bay leaves', 'fresh thyme', 'carrot', 'tahini', 'garlic', 'baby carrot', 'oranges', 'filo pastry', 'tomatoes', 'harissa', 'onions', 'rosemary', 'leg of lamb', 'vegetable bullion', 'sesame seeds', 'honey', 'anchovy fillets', 'vinegar', 'olive oil', 'couscous', 'fresh mint', 'celery', 'yoghurt'}), + ('baked_chicken_jollof_rice', 'Baked Chicken Jollof Rice', {'coriander', 'salt', 'white pepper', 'water', 'bell pepper', 'turmeric', 'rice', 'scotch bonnet pepper', 'chicken', 'thyme', 'maggi cubes', 'garlic', 'ginger', 'onion', 'tomato', 'carrot', 'tomato puree'}), + ('seafood_risotto', 'Seafood Risotto', {'white wine', 'water', 'clams', 'crab legs', 'baby squid', 'lemon juice', 'parmesan cheese', 'olive oil', 'white onion', 'garlic', 'arborio risotto rice', 'fish stock', 'mussels', 'flat-leaf parsley', 'tomato paste', 'prawns', 'baby scallops', 'cherry tomatoes'}), + ('lamb_over_marinated_summer_squash_with_hazelnuts_and_ricotta', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', {'red pepper flakes', 'hazelnuts', 'zucchini', 'bay leaves', 'carrot', 'garlic', 'white wine vinegar', 'toasted bread', 'lemon', 'onions', 'rosemary', 'leg of lamb', 'summer squash', 'sea salt', 'anchovy fillets', 'vinegar', 'olive oil', 'black pepper', 'fresh mint', 'celery', 'kosher salt', 'fresh ricotta', 'sugar'}) + ] + +############################## +# Data for test_check_drinks # +############################## + + +all_drinks = [('Amaretto Sour', ['almond liqueur', 'bourbon', 'cherries', 'egg white', 'lemon juice', 'lemon twist', 'simple syrup']), + ('Aperol Spritz', ['aperol', 'prosecco', 'soda water']), + ('Bannana Punch', ['banana', 'ginger ale', 'lemonade', 'orange juice', 'pineapple juice', 'sugar', 'water']), + ('Beet Sumac Soda', ['beet', 'club soda', 'fresh lemon juice', 'sugar', 'sumac']), + ('Better Than Celery Juice', ['apple cider vinegar', 'black pepper', 'celery stalks', 'club soda', 'granny smith apples', 'kosher salt', 'parsley']), + ('Black & Blue Berries', ['blackberries', 'blueberries', 'honey', 'lemon juice', 'soda water']), + ('Bloody Mary', ['celery', 'celery salt', 'lemon juice', 'pepper', 'tomato juice', 'vodka', 'worcestershire sauce']), + ('Bloody Shame', ['V8 juice', 'black pepper', 'celery', 'salt', 'tabasco sauce']), + ('Chai Blossom', ['chai tea bags', 'club soda', 'fresh lime juice', 'lemon twists', 'start anise pods', 'sugar']), + ('Chile-lime Pineapple Soda', ['chiles de Γ‘rbol', 'club soda', 'fresh pineapple juice', 'kosher salt', 'lime juice', 'lime wedges', 'pink peppercorns', 'sugar']), + ('Citrus Fizz', ['organic marmalade cordial', 'seedlip grove 42', 'sparkling water']), + ('Dry Martini', ['dry vermouth', 'gin', 'lemon twist', 'olives']), + ('Espresso Martini', ['coffee liqueur', 'espresso', 'sugar syrup', 'vodka']), + ('Fermented Grape Soda', ['red seedless grapes', 'sugar', 'washed organic ginger']), + ('French 75', ['champagne', 'gin', 'lemon juice', 'sugar syrup']), + ('Gimlet', ['gin', 'lime juice', 'sugar syrup']), + ('Gin Fizz', ['gin', 'lemon juice', 'soda water', 'sugar syrup']), + ('Huckleberry Shrub', ['club soda', 'huckleberries', 'sugar', 'white wine vinegar']), + ('Mai Tai', ['cherries', 'lime juice', 'lime wedge', 'mint leaves', 'orange curacao', 'orgeat syrup', 'rum', 'sugar syrup']), + ('Mango Mule', ['cucumber', 'fresh lime juice', 'ginger beer', 'honey syrup', 'ice', 'mango puree']), + ('Manhattan', ['bitters', 'cherry', 'rye', 'sweet vermouth']), + ('Maple-Ginger Cider Switchel', ['apple cider vinegar', 'club soda', 'fresh ginger', 'fresh lime juice', 'maple syrup', 'mint sprigs']), + ('Margarita', ['lime juice', 'salt', 'simple syrup', 'tequila', 'triple sec']), + ('Mojito', ['lime', 'mint leaves', 'soda water', 'sugar syrup', 'white rum']), + ('Moscow Mule', ['ginger beer', 'lime', 'lime juice', 'vodka']), + ('Negroni', ['bitters', 'gin', 'sweet vermouth']), + ('Old Fashioned', ['bitters', 'bourbon', 'orange juice', 'orange slices', 'sugar']), + ('PG13 Singapore Sling', ['fresh lime juice', 'mango juice', 'mint sprigs', 'pineapple juice', 'pomegranate juice', 'tonic water']), + ('Penicillin', ['ginger', 'honey simple syrup', 'lemon juice', 'scotch']), + ('Pina Colada', ['cherries', 'coconut milk', 'cream of coconut', 'dark rum', 'fresh pineapple', 'lime juice', 'white rum']), + ('Raspberry Almond Soda', ['almonds', 'club soda', 'kosher salt', 'limes', 'ripe raspberries', 'sugar']), + ('Salted Meyer Lemon and Sage Presse', ['club soda meyer lemons', 'kosher salt', 'sage leaves', 'simple syrup']), + ('Salted Watermelon Juice', ['cubed watermelon', 'kosher salt', 'lime wedges']), + ('Shirley Tonic', ['cinnamon sticks', 'club soda', 'ginger', 'lemon twists', 'pomegranate juice', 'sugar', 'whole cloves']), + ('Shirley ginger', ['brooklyn crafted lemon lime ginger beer', 'club soda', 'grenadine', 'lime juice']), + ('Spiced Hibiscus Tea', ['cinnamon sticks', 'dried hibiscus flowers', 'ginger', 'honey', 'lemon juice', 'lemon wheels', 'whole allspice']), + ('Turmeric Tonic', ['agave syrup', 'cayenne pepper', 'lemon', 'peeled ginger', 'peeled turmeric', 'sparkling water']), + ('Virgin Cucumber Gimlet', [';ime juice', 'club soda', 'muddled cucumber', 'simple syrup']), + ('Whiskey Sour', ['cherry', 'lemon juice', 'lemon slices', 'superfine sugar', 'whiskey']) + ] + +drink_names = ['Amaretto Sour Cocktail','Aperol Spritz Cocktail','Bannana Punch Mocktail','Beet Sumac Soda Mocktail', + 'Better Than Celery Juice Mocktail','Black & Blue Berries Mocktail','Bloody Mary Cocktail', + 'Bloody Shame Mocktail','Chai Blossom Mocktail','Chile-lime Pineapple Soda Mocktail', + 'Citrus Fizz Mocktail','Dry Martini Cocktail','Espresso Martini Cocktail','Fermented Grape Soda Mocktail', + 'French 75 Cocktail','Gimlet Cocktail','Gin Fizz Cocktail','Huckleberry Shrub Mocktail', + 'Mai Tai Cocktail','Mango Mule Mocktail','Manhattan Cocktail','Maple-Ginger Cider Switchel Mocktail', + 'Margarita Cocktail','Mojito Cocktail','Moscow Mule Cocktail','Negroni Cocktail', + 'Old Fashioned Cocktail','PG13 Singapore Sling Mocktail','Penicillin Cocktail','Pina Colada Cocktail', + 'Raspberry Almond Soda Mocktail','Salted Meyer Lemon and Sage Presse Mocktail', + 'Salted Watermelon Juice Mocktail','Shirley Tonic Mocktail','Shirley ginger Mocktail', + 'Spiced Hibiscus Tea Mocktail','Turmeric Tonic Mocktail','Virgin Cucumber Gimlet Mocktail', + 'Whiskey Sour Cocktail'] + + +################################# +# Data for test_categorize_dish # +################################# + +all_dishes = recipes_without_duplicates + +dishes_categorized = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt: PALEO', + 'Winter Cobb Salad: VEGETARIAN', + 'White Cheddar Scalloped Potatoes: VEGETARIAN', + 'Walnut Ravioli with Artichokes and Tomatoes: VEGETARIAN', + 'Waakye: VEGAN', + 'Vegetarian Khoresh Bademjan: VEGAN', + 'Vegan Pizza with Caramelized Onions: VEGAN', + 'Vegan Mini Savory Mince Pies: VEGAN', + 'Vegan Carbonara: VEGAN', + 'Sweet and Spicy Crispy Green Beans: VEGAN', + 'Summer Minestrone Cups: VEGETARIAN', + 'Sticky Lemon Tofu: VEGAN', + 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole: OMNIVORE', + 'Shakshuka: VEGAN', + 'Seared Salmon with Pickled Vegetable and Watercress Salad: KETO', + 'Seafood Risotto: OMNIVORE', + 'Satay Steak Skewers: KETO', + 'Roasted Corn and Zucchini Salad: VEGAN', + 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes: PALEO', + 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing: VEGETARIAN', + 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous: OMNIVORE', + 'Pumpkin Bread Crostini: PALEO', + 'Prawn and Herb Omelette: KETO', + 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus: KETO', + 'Parmesan Crackers and Spinach Crackers with Salmon Pate: KETO', + 'Nut Wellington: VEGETARIAN', + 'Mushroom Lasagna: VEGETARIAN', + 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta: OMNIVORE', + 'Kisir with Warm Pita: VEGAN', + 'Kingfish Lettuce Cups: KETO', + 'Grilled Tofu Tacos: VEGETARIAN', + 'Grilled Shrimp and Pesto over Zucchini Noodles: PALEO', + 'Grilled Pork Chops with Mango Pineapple Salsa: PALEO', + 'Grilled Flank Steak with Caesar Salad: PALEO', + 'Grilled Fish Tacos with Cauliflower Tortillas: PALEO', + 'Governor Shrimp Tacos: OMNIVORE', + 'Golden Potato Salad: VEGAN', + 'Georgian Eggplant Rolls with Walnuts: VEGAN', + 'Fried Zucchini with Balsamic and Chili Dressing: VEGETARIAN', + 'Fresh Garden Peas over Cauliflower Almond Puree: VEGETARIAN', + 'Flank Steak with Chimichurri and Asparagus: KETO', + 'Dahi Puri with Black Chickpeas: OMNIVORE', + 'Chicken with Tamarind and Apricot Sauce: PALEO', + 'Cherry Tomato, Watercress and Fava Bean Salad: VEGETARIAN', + 'Cheela with Spicy Mango Chutney: VEGAN', + 'Celeriac Schnitzel: VEGAN', + 'Cauliflower Pizza with Roasted Tomatoes and Chicken: KETO', + 'Carrot Puff Pastry Tart: VEGAN', + 'Cambodian-Style Vegetable Spring Rolls: VEGETARIAN', + 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney: KETO', + 'Burnt Masala Wings with Classic Coleslaw: OMNIVORE', + 'Burmese Tofu with Garlic, Ginger and Chili Sauce: VEGAN', + 'Brisket with Grilled Rhubarb, Onions, and Fennel: OMNIVORE', + 'Braised Pork Belly with Apple Salad: KETO', + 'BLT Bites: PALEO', + 'Beachside Snapper: OMNIVORE', + 'Barley Risotto: VEGETARIAN', + 'Baked Kelewele: VEGAN', + 'Baked Chicken Jollof Rice: OMNIVORE', + 'Avocado Deviled Eggs: PALEO', + 'Asparagus Puffs: VEGETARIAN'] + + +######################################### +# Data for test_tag_special_ingredients # +######################################### + + +dupes = ['Baked Kelewele', 'Barley Risotto', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', + 'Cambodian-Style Vegetable Spring Rolls', 'Fried Zucchini with Balsamic and Chili Dressing', + 'Kisir with Warm Pita', 'Shakshuka', 'Summer Minestrone Cups', 'Vegetarian Khoresh Bademjan'] + +nondupes = ['Brisket with Grilled Rhubarb, Onions, and Fennel', 'Burnt Masala Wings with Classic Coleslaw', + 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', + 'Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Dahi Puri with Black Chickpeas', + 'Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups', + 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole'] + +group_1 = [item for item in recipes_with_duplicates if item[0] in dupes] +group_2 = [(item[1], item[2]) for item in recipes_without_duplicates if item[1] in nondupes] + +dishes_to_special_label = sorted(group_1 + group_2) + +dishes_labeled = [('Baked Kelewele', {'red onion'}), + ('Barley Risotto', {'garlic', 'red onion', 'parmesan cheese'}), + ('Brisket with Grilled Rhubarb, Onions, and Fennel', {'soy sauce', 'garlic', 'red onion', 'yellow onion'}), + ('Burmese Tofu with Garlic, Ginger and Chili Sauce', {'soy sauce', 'garlic', 'peanuts'}), + ('Burnt Masala Wings with Classic Coleslaw', {'honey', 'butter', 'garlic cloves'}), + ('Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', {'heavy cream', 'garlic', 'butter', 'tomatoes'}), + ('Cambodian-Style Vegetable Spring Rolls', {'soy sauce', 'firm tofu', 'garlic', 'toasted peanuts'}), + ('Cauliflower Pizza with Roasted Tomatoes and Chicken', {'parmesan', 'mozzarella cheese', 'tomato paste', 'cherry tomatoes', 'eggs'}), + ('Dahi Puri with Black Chickpeas', {'red onion', 'whole-milk yogurt'}), + ('Flank Steak with Chimichurri and Asparagus', {'garlic'}), + ('Fried Zucchini with Balsamic and Chili Dressing', {'honey', 'garlic', 'red onion'}), + ('Kingfish Lettuce Cups', {'soy sauce', 'oyster sauce', 'garlic', 'grilled king fish'}), + ('Kisir with Warm Pita', {'bulgur', 'tomato paste'}), + ('Shakshuka', {'tomatoes', 'tomato paste', 'firm tofu', 'yellow onion'}), + ('Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', {'shrimp', 'garlic', 'butter', 'slivered almonds', 'bacon'}), + ('Summer Minestrone Cups', {'garlic', 'tomatoes', 'parmesan cheese'}), + ('Vegetarian Khoresh Bademjan', {'slivered almonds', 'tomato paste'})] + + +##################################### +# Data for test_compile_ingredients # +##################################### + + +ingredients_only = [[{'bulgur', 'pomegranate molasses', 'chopped parsley', 'lemon juice', 'tomato', 'persian cucumber', 'tomato paste', 'spring onion', 'water', 'olive oil'}, + {'vegan unsweetened yoghurt', 'yellow onion', 'firm tofu', 'smoked paprika', 'tomatoes', 'tomato paste', 'sugar', 'cloves', 'cumin', "za'atar", 'olive oil', 'harissa', 'red bell pepper'}, + {'yellow split peas', 'tomato paste', 'black pepper', 'pomegranate concentrate', 'yellow onions', 'slivered almonds', 'ground turmeric', 'barberries', 'basmati rice', 'lemon juice', 'hot water', 'cayenne pepper', 'chinese eggplants', 'salt', 'orange juice', 'saffron powder', 'vegan butter', 'orange zest', 'kosher salt'}, + {'smoked paprika', 'black peppercorn', 'red onion', 'grains of selim', 'cayenne pepper', 'calabash nutmeg', 'coconut oil', 'cloves', 'fresh ginger', 'salt', 'ripe plantains'}, + {'baking soda', 'sorghum stems', 'coconut oil', 'black-eyed peas', 'water', 'salt', 'white rice'}, + {'pomegranate seeds', 'oil', 'coriander', 'garlic', 'khmeli suneli', 'eggplants', 'black pepper', 'vinegar', 'walnuts', 'water', 'salt'}, + {'soy sauce', 'oil', 'chili flakes', 'garlic', 'brown sugar', 'ginger', 'peanuts', 'rice vinegar', 'spring onions', 'water', 'turmeric', 'salt', 'chickpea flour'}, + {'soy sauce', 'parsley', 'lemon', 'sunflower oil', 'black pepper', 'celeriac', 'breadcrumbs', 'water', 'salt', 'flour', 'chickpea flour'}, + {'soy sauce', 'vegetable stock', 'tofu', 'cornstarch', 'lemon juice', 'lemon zest', 'garlic', 'ginger', 'black pepper', 'sugar', 'water', 'salt', 'vegetable oil'}, + {'soy sauce', 'smoked tofu', 'lemon juice', 'nutritional yeast', 'mixed herbs', 'garlic', 'black pepper', 'silken tofu', 'turmeric', 'salt', 'olive oil', 'spaghetti'}, + {'mushrooms', 'rosemary', 'garlic', 'red pepper flakes', 'yeast', 'barley malt', 'water', 'olive oil', 'garlic powder', 'oregano', 'honey', 'nutritional yeast', 'red onion', 'tomatoes', 'cashews', 'sugar', 'bell pepper', 'flour', 'salt', 'fresh basil'}, + {'clove powder', 'oil', 'cinnamon powder', 'nigella seeds', 'curry leaves', 'coriander seeds', 'garlic', 'mangoes', 'mashed potatoes', 'cardamom powder', 'vinegar', 'water', 'mustard seeds', 'coriander powder', 'cumin powder', 'mango powder', 'garam masala', 'red chili powder', 'hing', 'garlic paste', 'turmeric powder', 'cilantro', 'sugar', 'onion', 'serrano chili', 'fresh ginger', 'turmeric', 'salt', 'fresh red chili', 'chickpea flour'}, + {'soy sauce', 'pomegranate molasses', 'sesame oil', 'green beans', 'sunflower oil', 'scallions', 'garlic', 'carrot', 'ginger', 'sesame seeds', 'tomato paste', 'bell pepper', 'siracha'}, + {'mushrooms', 'cinnamon powder', 'rosemary', 'corn flour', 'ginger', 'brown sugar', 'carrot', 'black pepper', 'raisins', 'butternut squash', 'vegetarian worcestershire sauce', 'parev shortcrust pastry', 'olive oil', 'vegetable stock', 'dried cherries', 'lemon juice', 'lemon zest', 'figs', 'dried cranberries', 'apples', 'pecans', 'onion', 'orange juice', 'currants', 'dried blueberries', 'salt', 'brandy', 'orange zest', 'allspice powder'}, + {'green onions', 'lemon juice', 'lemon zest', 'dill', 'corn', 'tomatoes', 'black pepper', 'zucchini', 'olive oil'}, + {'mustard seeds', 'cumin seeds', 'lemon juice', 'garlic', 'black pepper', 'balsamic vinegar', 'yukon gold potato', 'chives', 'turmeric', 'salt', 'olive oil'}, + {'olive oil', 'lemon', 'lemon juice', 'pareve puff pastry', 'brown sugar', 'red onion', 'carrot', 'garlic', 'black pepper', 'thyme', 'vegan butter', 'water', 'salt', 'ground almonds'} + ], + + [{'nutmeg', 'garlic', 'black pepper', 'onions', 'butter', 'parmesan cheese', 'portobello mushrooms', 'flour', 'dried lasagna noodles', 'olive oil', 'milk', 'kosher salt'}, + {'sage', 'puff pastry sheets', 'hazelnuts', 'almonds', 'black pepper', 'thyme', 'marmite', 'breadcrumbs', 'walnuts', 'dates', 'eggs', 'olive oil', 'brazil nuts', 'leeks', 'chestnuts', 'cashews', 'apples', 'pecans', 'butter', 'salt'}, + {'shallots', 'garlic', 'cream', 'thyme', 'breadcrumbs', 'sharp white cheddar', 'yukon gold potato', 'milk', 'kosher salt'}, + {'smoked tofu', 'shiitake mushrooms', 'red wine vinegar', 'garlic', 'tomatoes', 'black pepper', 'avocados', 'blue cheese', 'onion', 'lacinato kale', 'eggs', 'olive oil'}, + {'honey', 'lemon', 'dijon mustard', 'feta cheese', 'red wine vinegar', 'red onion', 'watercress', 'green lentils', 'currants', 'capers', 'pepitas', 'fresh pumpkin', 'olive oil'}, + {'lime juice', 'toasted peanuts', 'firm tofu', 'garlic', 'corn flour', 'bean sprouts', 'carrot', 'palm sugar', 'shallots', 'red chili', 'vermicelli noodles', 'wombok', 'soy sauce', 'sunflower oil', 'spring roll wrappers', 'vegetarian fish sauce'}, + {'fresh peas', 'rosemary', 'garlic', 'chickpeas', 'carrot', 'leek', 'green lentils', 'red chili', 'olive oil', 'croutons', 'fresh corn', 'lemon zest', 'green beans', 'parmesan rind', 'basil', 'tomatoes', 'vegetable bullion', 'parmesan cheese', 'celery', 'mint'}, + {'honey', 'lemon juice', 'garlic', 'red onion', 'red thai chili', 'pomegranate', 'balsamic vinegar', 'mint leaves', 'zucchini', 'olive oil'}, + {'sage', 'beets', 'pearl barley', 'brussel sprouts', 'rosemary', 'garlic', 'carrot', 'red onion', 'black pepper', 'thyme', 'butternut squash', 'vegetable bullion', 'parmesan cheese', 'olive oil', 'white wine'}, + {'fresh peas', 'fresh cherry tomatoes', 'garlic', 'watercress', 'balsamic vinegar', 'fresh or frozen fava beans', 'fresh cherry bocconcini', 'salt', 'olive oil'}, + {'red onions', 'lemon', 'fresh peas', 'garlic', 'grated nutmeg', 'cream', 'cauliflower', 'blanched almonds', 'fresh pea tendrils', 'olive oil', 'vegetable oil'}, + {'pine nuts', 'oil marinated artichokes', 'olives', 'rosemary', 'fresh tomatoes', 'ricotta cheese', 'black pepper', 'fresh artichoke hearts', 'walnuts', 'pasta sheets', 'lemon juice', 'lemon zest', 'basil', 'red onion', 'butter', 'salt'}, + {'egg', 'asparagus', 'lemon juice', 'red onion', 'ricotta cheese', 'black pepper', 'thyme', 'salt', 'parmesan cheese', 'puff pastry', 'chives'}, + {'cotija cheese', 'masa', 'fresh cilantro leaves', 'jalapeΓ±o chili', 'chipotle chili', 'firm tofu', 'garlic', 'carrot', 'roasted corn', 'tomatillos', 'pepitas', 'ancho chili', 'crema', 'red onions', 'pasilla chili', 'lemon', 'hot water', 'lemon juice', 'tomatoes', 'avocado', 'cumin', 'red cabbage', 'limes', 'black beans'} + ], + + [{'baking soda', 'coconut flour', 'lemon juice', 'lemon zest', 'eggs', 'coconut yogurt', 'black pepper', 'fresh thai chili', 'coconut oil', 'chives', 'zucchini', 'salt'}, + {'lime juice', 'fresh cilantro leaves', 'eggs', 'seranno chili', 'avocado', 'pepitas', 'salt', 'garlic powder'}, + {'pine nuts', 'white vinegar', 'chipotle chili', 'scallions', 'garlic', 'paleo parmesan cheese', 'black pepper', 'avocado oil', 'treviso', 'olive oil', 'radishes', 'flank steak', 'dijon mustard', 'castelfranco radicchio', 'worcestershire sauce', 'fresh parsley', 'cherry tomatoes', 'salt', 'avocado mayonnaise'}, + {'coconut flour', 'garlic', 'black pepper', 'cloves', 'eggs', 'olive oil', 'onions', 'honey', 'apple cider vinegar', 'almond butter', 'baking soda', 'nutmeg', 'pumpkin puree', 'cinnamon', 'shrimp', 'basil', 'coconut oil', 'cherry tomatoes', 'salt', 'fresh red chili'}, + {'mustard seed', 'onion', 'kale', 'cherry tomatoes', 'bacon', 'paleo mayonnaise'}, + {'purple sweet potato', 'chiles de Γ‘rbol', 'garlic', 'tomatoes', 'safflower oil', 'black pepper', 'mexican oregano', 'avocados', 'shallots', 'cumin', 'olive oil', 'lemons', 'whole chicken', 'limes', 'kosher salt'}, + {'garlic', 'black pepper', 'dried apricots', 'roma tomatoes', 'water', 'olive oil', 'honey', 'cinnamon', 'ground cumin', 'cider vinegar', 'chili powder', 'safflower oil', 'homemade tamarind concentrate', 'white chicken', 'allspice', 'chipotles', 'salt', 'homemade apricot honey preserves', 'kosher salt'}, + {'green onions', 'serrano chili', 'shredded red cabbage', 'smoked paprika', 'mango', 'eggs', 'black pepper', 'cilantro', 'cauliflower', 'avocado', 'lime', 'cumin', 'salt', 'tilapia'}, + {'cilantro leaves', 'lime', 'pineapple', 'chipotle chili', 'garlic', 'mangoes', 'cauliflower', 'avocado', 'serrano chili', 'pork chops', 'lime zest', 'lacinato kale', 'onions'}, + {'pine nuts', 'shrimp', 'green bell pepper', 'lemon juice', 'basil', 'lemon zest', 'garlic', 'tomatoes', 'cashews', 'yellow bell pepper', 'cumin', 'zucchini', 'salt', 'olive oil', 'red bell pepper'} + ], + + [{'parmesan', 'almond meal', 'rosemary', 'mozzarella cheese', 'roasted chicken', 'tomato paste', 'cauliflower', 'cherry tomatoes', 'eggs', 'fresh basil', 'olive oil'}, + {'white vinegar', 'asparagus', 'flank steak', 'chipotle chili', 'scallions', 'garlic', 'black pepper', 'cauliflower', 'sour cream', 'fresh parsley', 'salt', 'olive oil'}, + {'soy sauce', 'watermelon radishes', 'lime juice', 'fish sauce', 'mirin', 'little gem lettuce heads', 'peanut oil', 'garlic', 'sesame seeds', 'oyster sauce', 'spring onions', 'avocado', 'grilled king fish', 'red cabbage'}, + {'clove powder', 'curry leaves', 'coriander seeds', 'ginger', 'cardamom powder', 'vinegar', 'mustard seeds', 'mango powder', 'garam masala', 'red chili powder', 'chicken', 'hing', 'turmeric powder', 'tomatoes', 'ginger garlic paste', 'fresh greek yogurt', 'fresh ginger', 'monk fruit', 'turmeric', 'cashew nuts', 'salt', 'fresh red chili', 'cinnamon powder', 'nigella seeds', 'whole small crimini mushrooms', 'brussel sprouts', 'garlic', 'mangoes', 'heavy cream', 'cloves', 'coriander powder', 'cumin powder', 'cardamom', 'green chili', 'cinnamon', 'garlic paste', 'red chili flakes', 'lemon juice', 'cilantro', 'butter', 'dried fenugreek leaves', 'boned chicken'}, + {'green onions', 'parsley', 'sesame seeds', 'black pepper', 'chives', 'eggs', 'fennel bulb', 'tahini', 'olive oil', 'harissa', 'shrimp', 'lemon juice', 'dill', 'butter', 'onion', 'fresh cucumber', 'monk fruit', 'salt'}, + {'sriacha', 'apple cider vinegar', 'lime juice', 'fish sauce', 'red and green thai chili', 'flank steak', 'carrot', 'peanuts', 'cucumbers', 'roasted peanuts', 'crunchy peanut butter', 'kecap manis', 'monk fruit', 'micro cilantro', 'olive oil'}, + {'spinach', 'parmesan cheese', 'coconut flour', 'chili flakes', 'garlic', 'black pepper', 'cream cheese', 'ghee', 'lemon juice', 'flaxmeal', 'red onion', 'salt', 'salmon fillets', 'pecans', 'almond flour', 'cumin', 'fresh cucumber', 'cherry tomatoes', 'chives', 'avocado mayonnaise'}, + {'rosemary', 'garlic', 'black pepper', 'thyme', 'avocado oil', 'eggs', 'oregano', 'asparagus', 'lemon', 'dijon mustard', 'basil', 'castelfranco radicchio', 'dill', 'butter', 'pork chops', 'monk fruit', 'salt', 'avocado mayonnaise'}, + {'lime juice', 'caster sugar', 'toasted buckwheat', 'lemon juice', 'red wine vinegar', 'red onion', 'dutch carrot', 'salmon steaks', 'watercress', 'pink peppercorns', 'shallots', 'fennel seeds', 'red cabbage', 'radishes'}, + {'cilantro leaves', 'green cabbage', 'lemon juice', 'pork belly', 'dark soy sauce', 'granny smith apples', 'ginger', 'light soy sauce', 'sesame seeds', 'black pepper', 'cinnamon sticks', 'spring onions', 'star anise', 'monk fruit', 'olive oil'} + ], + + [{'lime juice', 'salsa', 'green bell pepper', 'anaheim chili', 'black pepper', 'olive oil', 'yellow mustard', 'red bell pepper', 'soy sauce', 'mexican crema', 'mayonnaise', 'white onion', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'tomatoes', 'limes', 'worcestershire sauce', 'butter', 'yellow bell pepper', 'salt', 'red snapper'}, + {'lime juice', 'poblano chili', 'tomato paste', 'black pepper', 'chipotle adobo sauce', 'chile manzano', 'roma tomatoes', 'pepitas', 'oaxaca cheese', 'white onion', 'shelled large shrimp', 'garlic cloves', 'fresh corn tortillas', 'red onion', 'worcestershire sauce', 'avocado', 'butter', 'kosher salt'}, + {'fresh tortillas', 'shrimp', 'garlic', 'chickpeas', 'black pepper', 'slivered almonds', 'guajillo chile', 'bacon', 'sea salt', 'butter', 'onion', 'avocado', 'olive oil'}, + {'lime juice', 'green cabbage', 'chiles de Γ‘rbol', 'green cardamom', 'ginger', 'carrot', 'sriracha', 'black pepper', 'cinnamon sticks', 'celery seeds', 'cloves', 'black cardamom', 'olive oil', 'chicken wings', 'apple cider vinegar', 'mayonnaise', 'honey', 'black peppercorns', 'lemon juice', 'garlic cloves', 'tamarind concentrate', 'cilantro', 'butter', 'serrano chili', 'red cabbage', 'kosher salt'}, + {'whole-milk yogurt', 'chaat masala', 'ginger', 'pani puri', 'scallion chutney', 'yukon gold potato', 'black chickpeas', 'thin sev', 'date syrup', 'red onion', 'roasted chicken', 'chili powder', 'tamarind concentrate', 'cumin', 'turmeric', 'mint'}, + {'white vinegar', 'parsley', 'yellow onion', 'rhubarb', 'garlic', 'brown sugar', 'black pepper', 'thyme', 'crushed red pepper flakes', 'fennel bulbs', 'beer', 'marjoram', 'vegetable oil', 'soy sauce', 'oregano', 'lemon', 'red onion', 'chili powder', 'cilantro', 'beef brisket', 'balsamic vinegar', 'worcestershire sauce', 'celery', 'mint', 'kosher salt'}, + {'oranges', 'rosemary', 'garlic', 'anchovy fillets', 'couscous', 'carrot', 'sesame seeds', 'fresh thyme', 'vinegar', 'olive oil', 'tahini', 'harissa', 'onions', 'honey', 'fresh mint', 'leg of lamb', 'tomatoes', 'baby carrot', 'vegetable bullion', 'filo pastry', 'celery', 'bay leaves', 'yoghurt'}, + {'tomato puree', 'garlic', 'ginger', 'tomato', 'carrot', 'thyme', 'white pepper', 'water', 'maggi cubes', 'chicken', 'rice', 'coriander', 'scotch bonnet pepper', 'bell pepper', 'onion', 'turmeric', 'salt'}, + {'garlic', 'tomato paste', 'baby scallops', 'mussels', 'water', 'crab legs', 'olive oil', 'baby squid', 'fish stock', 'lemon juice', 'white onion', 'arborio risotto rice', 'clams', 'parmesan cheese', 'flat-leaf parsley', 'cherry tomatoes', 'prawns', 'white wine'}, + {'toasted bread', 'rosemary', 'hazelnuts', 'anchovy fillets', 'garlic', 'carrot', 'summer squash', 'black pepper', 'red pepper flakes', 'vinegar', 'sea salt', 'zucchini', 'olive oil', 'onions', 'white wine vinegar', 'fresh mint', 'leg of lamb', 'lemon', 'fresh ricotta', 'sugar', 'celery', 'bay leaves', 'kosher salt'} + ]] + + +##################################### +# Data for test_separate_appetizers # +##################################### + + +vegan = ['Kisir with Warm Pita', 'Shakshuka', 'Vegetarian Khoresh Bademjan', 'Baked Kelewele', 'Waakye', 'Georgian Eggplant Rolls with Walnuts', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Celeriac Schnitzel', 'Sticky Lemon Tofu', 'Vegan Carbonara', 'Vegan Pizza with Caramelized Onions', 'Cheela with Spicy Mango Chutney', 'Sweet and Spicy Crispy Green Beans', 'Vegan Mini Savory Mince Pies', 'Roasted Corn and Zucchini Salad', 'Golden Potato Salad', 'Carrot Puff Pastry Tart', 'Kisir with Warm Pita', 'Baked Kelewele', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Vegan Carbonara', 'Sweet and Spicy Crispy Green Beans', 'Golden Potato Salad'] +vegan_appetizers = ['Georgian Eggplant Rolls with Walnuts', 'Cheela with Spicy Mango Chutney', 'Vegan Mini Savory Mince Pies', 'Carrot Puff Pastry Tart', 'Georgian Eggplant Rolls with Walnuts', 'Carrot Puff Pastry Tart'] +vegan_dishes = ['Golden Potato Salad', 'Roasted Corn and Zucchini Salad', 'Sticky Lemon Tofu', 'Shakshuka', 'Burmese Tofu with Garlic, Ginger and Chili Sauce', 'Vegan Pizza with Caramelized Onions', 'Celeriac Schnitzel', 'Waakye', 'Vegan Carbonara', 'Sweet and Spicy Crispy Green Beans', 'Vegetarian Khoresh Bademjan', 'Baked Kelewele', 'Kisir with Warm Pita'] +vegan_appetizer_names = ['Georgian Eggplant Rolls with Walnuts','Cheela with Spicy Mango Chutney','Vegan Mini Savory Mince Pies','Carrot Puff Pastry Tart'] + + +vegetarian = ['Mushroom Lasagna', 'Nut Wellington', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', 'Cambodian-Style Vegetable Spring Rolls', 'Summer Minestrone Cups', 'Fried Zucchini with Balsamic and Chili Dressing', 'Barley Risotto', 'Cherry Tomato, Watercress and Fava Bean Salad', 'Fresh Garden Peas over Cauliflower Almond Puree', 'Walnut Ravioli with Artichokes and Tomatoes', 'Asparagus Puffs', 'Grilled Tofu Tacos', 'Mushroom Lasagna', 'Cambodian-Style Vegetable Spring Rolls', 'Barley Risotto', 'Walnut Ravioli with Artichokes and Tomatoes'] +vegetarian_appetizers = ['Cambodian-Style Vegetable Spring Rolls', 'Summer Minestrone Cups', 'Asparagus Puffs', 'Grilled Tofu Tacos', 'Cambodian-Style Vegetable Spring Rolls', 'Grilled Tofu Tacos'] +vegetarian_dishes = ['Walnut Ravioli with Artichokes and Tomatoes', 'Mushroom Lasagna', 'Fried Zucchini with Balsamic and Chili Dressing', 'Barley Risotto', 'Nut Wellington', 'Cherry Tomato, Watercress and Fava Bean Salad', 'Roast Pumpkin and Lentil Salad with Roasted Lemon Dressing', 'Fresh Garden Peas over Cauliflower Almond Puree'] +vegetarian_appetizer_names = ['Cambodian-Style Vegetable Spring Rolls','Summer Minestrone Cups','Asparagus Puffs','Grilled Tofu Tacos'] + + +paleo = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Avocado Deviled Eggs', 'Grilled Flank Steak with Caesar Salad', 'Pumpkin Bread Crostini', 'BLT Bites', 'Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', 'Chicken with Tamarind and Apricot Sauce', 'Grilled Fish Tacos with Cauliflower Tortillas', 'Grilled Pork Chops with Mango Pineapple Salsa', 'Grilled Shrimp and Pesto over Zucchini Noodles', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Pumpkin Bread Crostini', 'Chicken with Tamarind and Apricot Sauce', 'Grilled Shrimp and Pesto over Zucchini Noodles'] +paleo_appetizers = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'Avocado Deviled Eggs', 'Pumpkin Bread Crostini', 'BLT Bites', 'Zucchini Fritters with Lemon-Thyme Coconut Yogurt', 'BLT Bites'] +paleo_dishes = ['Roasted Chicken with Roasted Tomatoes, Avocado, and Sweet Potatoes', 'Grilled Flank Steak with Caesar Salad', 'Grilled Fish Tacos with Cauliflower Tortillas', 'Grilled Pork Chops with Mango Pineapple Salsa', 'Grilled Shrimp and Pesto over Zucchini Noodles', 'Chicken with Tamarind and Apricot Sauce'] +paleo_appetizer_names = ['Zucchini Fritters with Lemon-Thyme Coconut Yogurt','Avocado Deviled Eggs','Pumpkin Bread Crostini','BLT Bites'] + + +keto = ['Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Flank Steak with Chimichurri and Asparagus', 'Kingfish Lettuce Cups', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Prawn and Herb Omelette', 'Satay Steak Skewers', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', 'Seared Salmon with Pickled Vegetable and Watercress Salad', 'Braised Pork Belly with Apple Salad', 'Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Braised Pork Belly with Apple Salad'] +keto_appetizers = ['Kingfish Lettuce Cups', 'Prawn and Herb Omelette', 'Satay Steak Skewers', 'Parmesan Crackers and Spinach Crackers with Salmon Pate', 'Kingfish Lettuce Cups', 'Parmesan Crackers and Spinach Crackers with Salmon Pate'] +keto_dishes = ['Cauliflower Pizza with Roasted Tomatoes and Chicken', 'Butter Chicken with Grilled Mushrooms, Brussel Sprouts and Mango Chutney', 'Braised Pork Belly with Apple Salad', 'Seared Salmon with Pickled Vegetable and Watercress Salad', 'Pork Chops with Grilled Castelfranco Radicchio and Asparagus', 'Flank Steak with Chimichurri and Asparagus'] +keto_appetizer_names = ['Kingfish Lettuce Cups','Prawn and Herb Omelette','Satay Steak Skewers','Parmesan Crackers and Spinach Crackers with Salmon Pate'] + + +omnivore = ['Beachside Snapper', 'Governor Shrimp Tacos', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', 'Burnt Masala Wings with Classic Coleslaw', 'Dahi Puri with Black Chickpeas', 'Brisket with Grilled Rhubarb, Onions, and Fennel', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Baked Chicken Jollof Rice', 'Seafood Risotto', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', 'Beachside Snapper', 'Burnt Masala Wings with Classic Coleslaw', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Lamb over Marinated Summer Squash with Hazelnuts and Ricotta'] +omnivore_appetizers = ['Governor Shrimp Tacos', 'Burnt Masala Wings with Classic Coleslaw', 'Dahi Puri with Black Chickpeas', 'Seafood Risotto', 'Governor Shrimp Tacos', 'Seafood Risotto'] +omnivore_dishes = ['Lamb over Marinated Summer Squash with Hazelnuts and Ricotta', 'Shrimp, Bacon and Crispy Chickpea Tacos with Salsa de Guacamole', 'Brisket with Grilled Rhubarb, Onions, and Fennel', 'Roast Leg of Lamb with Crispy Moroccan Carrots & Couscous', 'Beachside Snapper', 'Baked Chicken Jollof Rice'] +omnivore_appetizer_names = ['Governor Shrimp Tacos','Burnt Masala Wings with Classic Coleslaw','Dahi Puri with Black Chickpeas','Seafood Risotto'] + + +dishes_and_appetizers = ((vegan, vegan_appetizers), + (vegetarian, vegetarian_appetizers), + (paleo, paleo_appetizers), + (keto, keto_appetizers), + (omnivore, omnivore_appetizers) + ) + +dishes_cleaned = (vegan_dishes, + vegetarian_dishes, + paleo_dishes, + keto_dishes, + omnivore_dishes + ) + + +####################################### +# Data for test_singleton_ingredients # +####################################### + + +intersections = (VEGAN_INTERSECTIONS, VEGETARIAN_INTERSECTIONS, PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, OMNIVORE_INTERSECTIONS) + +dishes_and_overlap = [(item[0], item[1]) for item in zip(ingredients_only, intersections)] +ingredients = (set.union(*group) for group in ingredients_only) +singletons = (item[0] ^ item[1] for item in zip(ingredients, intersections)) + +backup_singletons = [{'black-eyed peas', 'coriander', 'cashews', 'yellow split peas', 'pomegranate seeds', 'cumin', 'mangoes', 'pomegranate concentrate', 'red chili powder', 'slivered almonds', 'black peppercorn', 'cornstarch', 'smoked tofu', 'curry leaves', 'zucchini', 'currants', 'dried cranberries', 'yukon gold potato', 'tofu', 'yeast', 'fresh basil', 'hot water', 'ripe plantains', 'calabash nutmeg', 'green beans', 'kosher salt', 'grains of selim', 'vegetarian worcestershire sauce', 'cumin seeds', 'figs', 'ground turmeric', 'white rice', 'harissa', 'garlic powder', 'scallions', 'barberries', 'walnuts', 'basmati rice', 'saffron powder', 'butternut squash', 'thyme', 'tomato', 'chopped parsley', 'hing', 'coriander seeds', 'turmeric powder', 'eggplants', 'sesame oil', "za'atar", 'pareve puff pastry', 'firm tofu', 'yellow onions', 'coriander powder', 'parsley', 'garlic paste', 'rice vinegar', 'sorghum stems', 'spring onions', 'raisins', 'chinese eggplants', 'garam masala', 'ground almonds', 'baking soda', 'clove powder', 'allspice powder', 'parev shortcrust pastry', 'dill', 'nigella seeds', 'dried blueberries', 'cardamom powder', 'cilantro', 'serrano chili', 'breadcrumbs', 'mango powder', 'dried cherries', 'oregano', 'fresh red chili', 'pecans', 'chives', 'spaghetti', 'mixed herbs', 'brandy', 'cumin powder', 'silken tofu', 'yellow onion', 'balsamic vinegar', 'persian cucumber', 'red bell pepper', 'peanuts', 'siracha', 'red pepper flakes', 'spring onion', 'vegan unsweetened yoghurt', 'corn', 'khmeli suneli', 'barley malt', 'green onions', 'apples', 'corn flour', 'honey', 'celeriac', 'bulgur', 'sesame seeds', 'mashed potatoes', 'chili flakes', 'vegetable oil'}, +{'vegetarian fish sauce', 'cashews', 'white wine', 'portobello mushrooms', 'marmite', 'dates', 'tomatillos', 'cumin', 'chestnuts', 'beets', 'masa', 'mint', 'smoked tofu', 'fresh pea tendrils', 'puff pastry sheets', 'zucchini', 'currants', 'hazelnuts', 'croutons', 'pearl barley', 'dijon mustard', 'yukon gold potato', 'fresh tomatoes', 'vermicelli noodles', 'fresh cherry tomatoes', 'celery', 'hot water', 'green beans', 'grated nutmeg', 'roasted corn', 'palm sugar', 'ancho chili', 'fresh corn', 'spring roll wrappers', 'cotija cheese', 'parmesan rind', 'pasta sheets', 'brazil nuts', 'cauliflower', 'butternut squash', 'mint leaves', 'fresh cherry bocconcini', 'crema', 'blue cheese', 'chickpeas', 'pasilla chili', 'black beans', 'wombok', 'capers', 'pine nuts', 'egg', 'shiitake mushrooms', 'red thai chili', 'jalapeΓ±o chili', 'toasted peanuts', 'brussel sprouts', 'lime juice', 'leeks', 'flour', 'dried lasagna noodles', 'onions', 'limes', 'chipotle chili', 'lacinato kale', 'fresh pumpkin', 'almonds', 'olives', 'onion', 'fresh artichoke hearts', 'leek', 'pecans', 'chives', 'blanched almonds', 'nutmeg', 'fresh or frozen fava beans', 'soy sauce', 'avocados', 'bean sprouts', 'asparagus', 'feta cheese', 'sharp white cheddar', 'apples', 'sunflower oil', 'corn flour', 'avocado', 'puff pastry', 'red cabbage', 'pomegranate', 'fresh cilantro leaves', 'oil marinated artichokes', 'vegetable oil'}, +{'treviso', 'cashews', 'mexican oregano', 'pumpkin puree', 'purple sweet potato', 'homemade apricot honey preserves', 'apple cider vinegar', 'homemade tamarind concentrate', 'paleo parmesan cheese', 'pineapple', 'green bell pepper', 'chipotles', 'nutmeg', 'ground cumin', 'coconut yogurt', 'kale', 'mangoes', 'red bell pepper', 'dried apricots', 'garlic powder', 'pepitas', 'white vinegar', 'scallions', 'avocados', 'shredded red cabbage', 'smoked paprika', 'lime juice', 'flank steak', 'fresh parsley', 'shallots', 'chiles de Γ‘rbol', 'yellow bell pepper', 'white chicken', 'whole chicken', 'chili powder', 'bacon', 'avocado mayonnaise', 'cilantro', 'limes', 'lemons', 'green onions', 'avocado oil', 'cloves', 'lacinato kale', 'lime zest', 'paleo mayonnaise', 'radishes', 'mango', 'dijon mustard', 'mustard seed', 'cider vinegar', 'pork chops', 'castelfranco radicchio', 'water', 'allspice', 'seranno chili', 'cilantro leaves', 'onion', 'tilapia', 'fresh cilantro leaves', 'worcestershire sauce', 'almond butter', 'fresh thai chili', 'fresh red chili', 'chives', 'roma tomatoes'}, +{'dried fenugreek leaves', 'apple cider vinegar', 'cinnamon sticks', 'roasted chicken', 'cumin', 'mangoes', 'heavy cream', 'micro cilantro', 'white vinegar', 'red chili powder', 'cinnamon powder', 'mustard seeds', 'red wine vinegar', 'mirin', 'cinnamon', 'green chili', 'avocado oil', 'curry leaves', 'star anise', 'dijon mustard', 'crunchy peanut butter', 'grilled king fish', 'chicken', 'fresh basil', 'cashew nuts', 'pink peppercorns', 'pork belly', 'spinach', 'watercress', 'whole small crimini mushrooms', 'coconut flour', 'fresh ginger', 'fennel bulb', 'harissa', 'tahini', 'mozzarella cheese', 'scallions', 'sriacha', 'fresh parsley', 'thyme', 'light soy sauce', 'cream cheese', 'hing', 'coriander seeds', 'sour cream', 'turmeric powder', 'castelfranco radicchio', 'parmesan', 'toasted buckwheat', 'coriander powder', 'dark soy sauce', 'granny smith apples', 'parsley', 'shrimp', 'garlic paste', 'roasted peanuts', 'turmeric', 'carrot', 'garam masala', 'clove powder', 'cucumbers', 'tomato paste', 'almond meal', 'dutch carrot', 'brussel sprouts', 'red and green thai chili', 'shallots', 'nigella seeds', 'cardamom powder', 'watermelon radishes', 'flaxmeal', 'cilantro', 'fennel seeds', 'chipotle chili', 'ghee', 'parmesan cheese', 'radishes', 'pork chops', 'cilantro leaves', 'fresh greek yogurt', 'cardamom', 'mango powder', 'onion', 'oregano', 'fresh red chili', 'pecans', 'salmon fillets', 'basil', 'green cabbage', 'cumin powder', 'almond flour', 'lemon', 'boned chicken', 'oyster sauce', 'soy sauce', 'little gem lettuce heads', 'peanut oil', 'peanuts', 'caster sugar', 'salmon steaks', 'ginger garlic paste', 'green onions', 'vinegar', 'cloves', 'kecap manis', 'avocado', 'chili flakes', 'red chili flakes', 'tomatoes'}, +{'coriander', 'white wine', 'fish stock', 'apple cider vinegar', 'salsa', 'rhubarb', 'beef brisket', 'cinnamon sticks', 'cumin', 'roasted chicken', 'chicken wings', 'white vinegar', 'sriracha', 'slivered almonds', 'fresh thyme', 'scotch bonnet pepper', 'zucchini', 'hazelnuts', 'pani puri', 'yukon gold potato', 'toasted bread', 'chicken', 'yoghurt', 'maggi cubes', 'couscous', 'roma tomatoes', 'celery seeds', 'chaat masala', 'white pepper', 'black cardamom', 'harissa', 'red snapper', 'green cardamom', 'crushed red pepper flakes', 'tahini', 'mexican crema', 'chiles de Γ‘rbol', 'tomato', 'baby squid', 'mussels', 'chipotle adobo sauce', 'shelled large shrimp', 'tomato puree', 'chickpeas', 'fresh tortillas', 'flat-leaf parsley', 'anaheim chili', 'parsley', 'shrimp', 'chile manzano', 'vegetable bullion', 'prawns', 'cherry tomatoes', 'marjoram', 'beer', 'green bell pepper', 'date syrup', 'guajillo chile', 'baby scallops', 'yellow mustard', 'black chickpeas', 'bell pepper', 'filo pastry', 'thin sev', 'bacon', 'white wine vinegar', 'limes', 'rice', 'serrano chili', 'brown sugar', 'parmesan cheese', 'poblano chili', 'fennel bulbs', 'clams', 'baby carrot', 'arborio risotto rice', 'oregano', 'oaxaca cheese', 'green cabbage', 'yellow onion', 'balsamic vinegar', 'whole-milk yogurt', 'sugar', 'red bell pepper', 'pepitas', 'red pepper flakes', 'oranges', 'yellow bell pepper', 'summer squash', 'cloves', 'red cabbage', 'black peppercorns', 'fresh ricotta', 'crab legs', 'scallion chutney', 'sesame seeds', 'vegetable oil'}] \ No newline at end of file From 46311f34b2aa11c042e9a4dd05c350844c922dc2 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:52:05 -0700 Subject: [PATCH 05/34] Deleted unneeded sets files. --- exercises/concept/sets/.DS_Store | Bin 10244 -> 0 bytes exercises/concept/sets/.docs/after.md | 167 ------------------- exercises/concept/sets/.docs/hints.md | 36 ---- exercises/concept/sets/.docs/instructions.md | 109 ------------ exercises/concept/sets/.docs/introduction.md | 66 -------- exercises/concept/sets/.meta/config.json | 10 -- exercises/concept/sets/.meta/design.md | 68 -------- exercises/concept/sets/.meta/exemplar.py | 21 --- exercises/concept/sets/sets.py | 19 --- exercises/concept/sets/sets_test.py | 128 -------------- 10 files changed, 624 deletions(-) delete mode 100644 exercises/concept/sets/.DS_Store delete mode 100644 exercises/concept/sets/.docs/after.md delete mode 100644 exercises/concept/sets/.docs/hints.md delete mode 100644 exercises/concept/sets/.docs/instructions.md delete mode 100644 exercises/concept/sets/.docs/introduction.md delete mode 100644 exercises/concept/sets/.meta/config.json delete mode 100644 exercises/concept/sets/.meta/design.md delete mode 100644 exercises/concept/sets/.meta/exemplar.py delete mode 100644 exercises/concept/sets/sets.py delete mode 100644 exercises/concept/sets/sets_test.py diff --git a/exercises/concept/sets/.DS_Store b/exercises/concept/sets/.DS_Store deleted file mode 100644 index 2bb0c136774818d4bc29a458d2cf55aab3eb093a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHMO>7%Q6n^V&Xws&M?X-~o2w4qCMPPf^ze#$)aov(gR0*_HDHPJRy>?dF>{?zY zX%UAYaRiCKV}&YC94m3)f}n7vLgj|4qP9Xp6+)sMkb0YTn*t969{5i^!1*DD!fipc>t5@o4pi3uy&LR1o;7?LNB@fc4>TM+HK*Lvb4dEz9Al_l|oBDt$WF6K@r zso=Fi9e5z{K(7b*+r5txR3)1#o4?;X*hXcwQ8w)|F8cfBhG{r0MY$G^NTDrq-$Psb z2exe=+%Ys9jzmXx?s_=-NOW{`boc0PJrFzq-9&2b7!>Z4>^fN7HE`*~SLawUk_3A4dtm9`Jn-#lr zo@wg3HJh4M*NbOgHnp;D&RRvg)v}jaoV8(7b4{J)#-6_AMPN1(y2uDM@>u_j zwd7Q^hVBh+s;_Ln5uJV#A;RQvVq>?7mQky1n)#PHBhWYE&-@)kv_oW4pW9(hn3M9A z!ROw^SVZ9WfH?<;Xt!_nWUpOAv>%B)L1of#td^)wO&qWlvT)E6)FOjw_%}>ZXq^Ff zi5$$+s6je-kz}vN5pYk~=E}0}B>jbnc1kU_8#Q(@c$7~}%XSuH(hPvUDfbF5!_ULChX(1W>vsd5ZNcvjE#h%H zO(pm??OKuCWJR)VMccJqt{EXINw6bCJNe9T87s_r+Z`*M^uYlSghOK=3@N0^UY8ow5AMl$V zq%iOWfeXOr1x5^Mo-+X`6vG_oVd{$!ed{9V1;(FC5rBQdXHnog9-Bsh2L(R{JS}hm zcu`>KG7S;9syM=;HAh3a`zwGW1?IFwoKW)1E)>r$t}KDaTW=rb_Yr)Ztt@UrgmvQz_prL)i8+Hs#wW)DrvnJPhU_ zvR*eI0Phg}O_>2anD5SO=Lqz737#L1u597@pX1Pi{x?w0pbL_un4EyzbCa-3z+IT*zs=4yGRs*Q1T1u^C#%t9|R#9uYTqTR_(@sG50DmX5 zWqf@pC6!9$CiI+}*;e?O)%CQf`p>nbpYOWk&)JBx9iKC%2nuJr%e;9IXS)L&P*8Wa zD+qolM)Z@weZZ&u`M{>Y5#aLzbB0?Nm^0kl0>^+a39JBLCXb|x-u>oY1enh$Q}iOy zoS5I8`ECn7@5hZ{?;8o7#u)FNZecB)LC$6W#9sU}&g-->*77lLCyc`PFoVlpKzUZQ zpE4hN(Q0~Lov0$%x{_9ubh?sJ)0tW>U#sajbBdOp$d6~T<<4^l(T=RYdaQ|e9IMU> zQ347)5P0B!;sGQlrWpVJe;CPvpNs(o9tb?}V0l22OUFt@?D=j_aDMBFp`1ox;(6;{ z>x!UqUyRW5+Xr{}jrss%@Dy&DfD58s_gZj3|N4IhcrVCq9en=>-~aCK0}t5u{~zXB Bu517R diff --git a/exercises/concept/sets/.docs/after.md b/exercises/concept/sets/.docs/after.md deleted file mode 100644 index af22c5ded1..0000000000 --- a/exercises/concept/sets/.docs/after.md +++ /dev/null @@ -1,167 +0,0 @@ -# After - -In Python, a [tuple](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/tuple.md) is an immutable collection of items in _sequence_. Like most collections (_see the built-ins [`list`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/list.md), [`dict`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/dict.md) and [`set`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/set.md)_), tuples can hold any (or multiple) data type(s) -- including other tuples. Like any [sequence](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range), items are referenced by 0-based index number, and can be copied in whole or in part via _slice notation_. Tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). - -Tuples take up very little memory space compared to other collection types and have constant (_O(1)_) access time. However, they cannot be resized, sorted, or altered once created, so are less flexible when frequent changes or updates to data are needed. - -## Tuple Construction - -Tuples can be formed in multiple ways, using either the `tuple` class constructor or the `tuple` literal declaration. - -### Using the `tuple()` constructor empty or with an _iterable_: - -```python ->>> no_elements = tuple() -() - -#the string elements (characters) are iterated through and added to the tuple ->>> multiple_elements_string = tuple("Timbuktu") -('T', 'i', 'm', 'b', 'u', 'k', 't', 'u') - ->>> multiple_elements_list = tuple(["Parrot", "Bird", 334782]) -("Parrot", "Bird", 334782) - ->>> multiple_elements_set = tuple({2, 3, 5, 7, 11}) -(2,3,5,7,11) - - -""" -The iteration default for dictionaries is over the keys. -To include both keys and values in a tuple made from a dictionary, use dict.items(), -which returns a list of (key, value) tuples. -""" -source_data = {"fish": "gold", "monkey": "brown"} ->>> multiple_elements_dict_1 = tuple(source_data) -('fish', 'monkey') - ->>> multiple_elements_dict_2 = tuple(source_data.items()) -(('fish', 'gold'), ('monkey', 'brown')) - - -""" -because the tuple constructor only takes _iterables_ (or nothing), it is much easier to create - a one-tuple via the literal method. -""" ->>> one_element = tuple([16]) -(16,) - -``` - -#### Declaring a tuple as a _literal_ : - -```python ->>> no_elements = () -() - ->>> one_element = ("Guava",) -("Guava",) - ->>> elements_separated_with_commas = "Parrot", "Bird", 334782 -("Parrot", "Bird", 334782) - ->>> elements_with_commas_and_parentheses = ("Triangle", 60, 60, 60) -("Triangle", 60, 60, 60) - ->>> nested_data_structures = ({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) -({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) - -#using the plus + operator unpacks each tuple and creates a new tuple. ->>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") -("George", 5, "cat", "Tabby") - -#likewise, using the multiplication operator * is the equvilent of using + n times ->>> first_group = ("cat", "dog", "elephant") - ->>> multiplied_group = first_group * 3 -('cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant') - -``` - -Note that generally parentheses are not _required_ to create a `tuple` literal - only commas. Parentheses are required in cases of ambiguity, such as an empty or one-item tuple or where a function takes a tuple as an argument. - -## Tuples as related information - -Tuples are often used as _records_ containing heterogeneous data that is _organizationally_ or _conceptually_ related and treated as a single unit of information. - -```python - ->>> student_info = ("Alyssa", "grade 3", "female", 8 ) - -``` - -Tuples are also used when homogeneous immutable sequences of data are needed for [`hashability`](https://docs.python.org/3/glossary.html#hashable), storage in a set, or creation of keys in a dictionary. - -Note that while tuples are in most cases _immutable_, because they can contain _any_ data structure or object they can become mutable if any of their elements is a _mutable type_. Using a mutable data type within a tuple will make the enclosing tuple un-hashable. - -```python - ->>> cmyk_color_map = { - (.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292), - (0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01), - (.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E), - (0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C) - } - ->>>> unique_rgb_colors = { - (59, 178, 146), - (247, 127, 1), - (89, 16, 142), - (140, 0, 76), - (76, 0, 140) - } - ->>> teal_700 = hash((59, 178, 146)) - ->>> teal_700 = hash(("Pantone 228", [(140, 0, 76), 0x8C004C])) -Traceback (most recent call last): - File "", line 1, in -TypeError: unhashable type: 'list' - -``` - -## Accessing data inside a tuple - -Items inside tuples (_like the sequence types `string` and `list`_), can be accessed via 0-based index and _bracket notation_. Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). - -Items inside tuples can also be _iterated over_ in a loop using `for item in` syntax. - -```python - ->>> student_info = ("Alyssa", "grade 3", "female", 8 ) - -#name is at index 0 or index -4 ->>> student_name = student_info[0] -Alyssa - ->>> student_name = student_info[-4] -Alyssa - -#grade is at index 1 or index -3 ->>> student_grade = student_info[1] -'grade 3' - ->>> student_grade = student_info[-3] -'grade 3' - -#age is at index 3 or index -1 ->>> student_age_1 = student_info[3] -8 - ->>> student_age_2 = student_info[-1] -8 - - ->>> for item in student_info: ->>> print(item) - -.... -Alyssa -grade 3 -female -8 - -``` - -## Extended tuples and related data types - -Tuples are often used as _records_, but the data inside them can only be accessed via _position_/_index_. The [`namedtuple()`](https://docs.python.org/3/library/collections.html#collections.namedtuple) class in the [`collections`](https://docs.python.org/3/library/collections.html#module-collections) module extends basic tuple functionality to allow access of elements by _name_. Additionally, users can adapt a [`dataclass`](https://docs.python.org/3/library/dataclasses.html) to provide similar named attribute functionality, with a some [pros and cons](https://stackoverflow.com/questions/51671699/data-classes-vs-typing-namedtuple-primary-use-cases). diff --git a/exercises/concept/sets/.docs/hints.md b/exercises/concept/sets/.docs/hints.md deleted file mode 100644 index e61112972e..0000000000 --- a/exercises/concept/sets/.docs/hints.md +++ /dev/null @@ -1,36 +0,0 @@ -# Hints - -## General - -- [Tuples](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences) are immutable. - [Sequence Types](https://docs.python.org/3/library/stdtypes.html#typesseq) that can contain any data type. -- Tuples are [iterable](https://docs.python.org/3/glossary.html#term-iterable). -- Elements within tuples can be accessed via [bracket notation](https://stackoverflow.com/questions/30250282/whats-the-difference-between-the-square-bracket-and-dot-notations-in-python), using a zero-based index. -- Other [Common Sequence Operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) can also be used when working with tuples. - -## 1. Extract coordinates - -- Remember: tuples allow access via _index_, using _brackets_. Indexes start from the left at zero. - -## 2. Format coordinates - -- Check [`class tuple`](https://docs.python.org/3/library/stdtypes.html#tuple) for more details on tuples. -- Check [`class str`](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) for more details on strings. - -## 3. Match coordinates - -- What methods could be used here for for [testing membership](https://docs.python.org/3/reference/expressions.html#membership-test-operations)?. -- Check [`class tuple`](https://docs.python.org/3/library/stdtypes.html#tuple) for more details on tuples. -- Could you re-use your `convert_coordinate()` function? - -## 4. Combine matched records - -- Remember that tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). -- Could you re-use your `compare_records()` function here? - -## 5. "Clean up" & format a report of all records - -- Remember: tuples are _immutable_, but the contents can be accessed via _index_ using _bracket notation_. -- Tuples don't have to use parentheses unless there is _ambiguity_. -- Python has multiple methods of string formatting. [`str.format()`](https://docs.python.org/3/library/stdtypes.html#str.format) and [`f-strings`](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) are two very common ones. -- There are multiple textual formatting options available via Pythons [`format specification mini-language`](https://docs.python.org/3/library/string.html#format-specification-mini-language). diff --git a/exercises/concept/sets/.docs/instructions.md b/exercises/concept/sets/.docs/instructions.md deleted file mode 100644 index a2d506bfae..0000000000 --- a/exercises/concept/sets/.docs/instructions.md +++ /dev/null @@ -1,109 +0,0 @@ -# Instructions - -Aazra and Rui are teammates competing in a pirate-themed treasure hunt. One has a list of treasures with map coordinates, the other a list of location names with map coordinates. They've also been given blank maps with a starting place marked YOU ARE HERE. - -
- - - -
Azara's ListRui's List
- -| Treasure | Coordinates | -| --------------------------- | ----------- | -| Amethyst Octopus | 1F | -| Angry Monkey Figurine | 5B | -| Antique Glass Fishnet Float | 3D | -| Brass Spyglass | 4B | -| Carved Wooden Elephant | 8C | -| Crystal Crab | 6A | -| Glass Starfish | 6D | -| Model Ship in Large Bottle | 8A | -| Pirate Flag | 7F | -| Robot Parrot | 1C | -| Scrimshaw Whale's Tooth | 2A | -| Silver Seahorse | 4E | -| Vintage Pirate Hat | 7E | - - - -| Location Name | Coordinates | Quandrant | -| ------------------------------------- | ----------- | --------- | -| Seaside Cottages | ("1", "C") | Blue | -| Aqua Lagoon (Island of Mystery) | ("1", "F") | Yellow | -| Deserted Docks | ("2", "A") | Blue | -| Spiky Rocks | ("3", "D") | Yellow | -| Abandoned Lighthouse | ("4", "B") | Blue | -| Hidden Spring (Island of Mystery) | ("4", "E") | Yellow | -| Stormy Breakwater | ("5", "B") | Purple | -| Old Schooner | ("6", "A") | Purple | -| Tangled Seaweed Patch | ("6", "D") | Orange | -| Quiet Inlet (Island of Mystery) | ("7", "E") | Orange | -| Windswept Hilltop (Island of Mystery) | ("7", "F") | Orange | -| Harbor Managers Office | ("8", "A") | Purple | -| Foggy Seacave | ("8", "C") | Purple | - -
- -
- -But things are a bit disorganized: Azara's coordinates appear to be formatted and sorted differently from Rui's, and they have to keep looking from one list to the other to figure out which treasures go with which locations. Being budding pythonistas, they've come to you for help in writing a small program (a set of functions, really) to better organize their hunt information. - -## 1. Extract coordinates - -Implement the `get_cooordinate()` function that takes a `(treasure, coordinate)` pair from Azaras list and returns only the extracted map coordinate. -​ - -```python ->>> get_coordinate(("Scrimshaw Whale's Tooth", "2A")) -"2A" -``` - -## 2. Format coordinates - -Implement the `convert_coordinate()` function that takes a coordinate in the format "2A" and returns a tuple in the format `("2", "A")`. - -​ - -```python ->>> convert_coordinate("2A") -("2", "A") -``` - -## 3. Match coordinates - -Implement the `compare_records()` function that takes a `(treasure, coordinate)` pair and a `(location, coordinate, quadrant)` record and compares coordinates from each. Return **`True`** if the coordinates "match", and return **`False`** if they do not. Re-format coordinates as needed for accurate comparison. - -```python ->>> compare_records(('Brass Spyglass', '4B'),('Seaside Cottages', ("1", "C"), 'blue')) -False - ->>> compare_records(('Model Ship in Large Bottle', '8A'), ('Harbor Managers Office', ("8", "A"), 'purple')) -True -``` - -## 4. Combine matched records - -Implement the `create_record()` function that takes a `(treasure, coordinate)` pair from Azaras list and a `(location, coordinate, quadrant)` record from Ruis list and returns `(treasure, coordinate, location, coordinate, quadrant)` **if the coordinates match**. If the coordinats _do not_ match, return the string "not a match.". Re-format the coordinate as needed for accurate comparison. - -```python ->>> create_record(('Brass Spyglass', '4B'),('Abandoned Lighthouse', ("4", "B"), 'Blue')) -('Brass Spyglass', '4B', 'Abandoned Lighthouse', ("4", "B"), 'Blue') - ->>> create_record(('Brass Spyglass', '4B'),(("1", "C"), 'Seaside Cottages', 'blue')) -"not a match." -``` - -## 5. "Clean up" & make a report of all records - -Clean up the combined records from Azara and Rui so that there's only one set of coordinates per record. Make a report so they can see one list of everything they need to put on their maps. -Implement the `clean_up()` function that takes a tuple of tuples (_everything from both lists_), looping through the _outer_ tuple, dropping the unwanted coordinates from each _inner_ tuple and adding each to a 'report'. Format and return the 'report' so that there is one cleaned record on each line. - -```python ->>> clean_up((('Brass Spyglass', '4B', 'Abandoned Lighthouse', '("4", "B")', 'Blue'), ('Vintage Pirate Hat', '7E', 'Quiet Inlet (Island of Mystery)', '("7", "E")', 'Orange'), ('Crystal Crab', '6A', 'Old Schooner', '("6", "A")', 'Purple'))) - -""" -('Brass Spyglass', 'Abandoned Lighthouse', '("4", "B")', 'Blue')\n -('Vintage Pirate Hat', 'Quiet Inlet (Island of Mystery)', '("7", "E")', 'Orange')\n -('Crystal Crab', 'Old Schooner', '("6", "A")','Purple')\n -""" -``` diff --git a/exercises/concept/sets/.docs/introduction.md b/exercises/concept/sets/.docs/introduction.md deleted file mode 100644 index 8fb3a29c2e..0000000000 --- a/exercises/concept/sets/.docs/introduction.md +++ /dev/null @@ -1,66 +0,0 @@ -# Introduction - -In Python, a [set](https://docs.python.org/3/library/stdtypes.html#set) is an _unordered_ collection of distinct _hashable_ objects. Like most collections, sets can hold any (or multiple) data type(s) -- as long as those types can be [hashed](https://docs.python.org/3.7/glossary.html#term-hashable). Sets come in two flavors: _mutable_ (`set`) and _immutable_ (`frozenset`). - -Sets are most commonly used to remove duplicates from sequences, test for membership (_finding supersets & subsets_), and performing "set math" (_union, intersection, difference & symmetric difference_). - -Like other collection types such as `dict`, `list`, & `tuple`, `sets` support membership testing through `in`, length calculation through `len()` & _iteration_ via `for item in set`. Unlike the `sequence types` `string`, `list` & `tuple`, `sets` are neither ordered nor indexed, and **do not support** indexing, slicing, sorting, or other sequence behavior. - -## Set Construction - -Sets can be formed multiple ways, using either the `set` class constructor or the `set` literal declaration. - -### Using the `set()` constructor: - -```python -#elements are iterated through and added to the set. Sets are unordered, duplicates are not allowed. ->>> multiple_elements_string = set("Timbuktu") -{'m', 't', 'u', 'b', 'k', 'T', 'i'} - ->>> multiple_elements = set(["Parrot", "Seagull", "Kingfisher", "Pelican", "Seagull", "Kingfisher", "Kingfisher"]) -{'Seagull', 'Kingfisher', 'Pelican', 'Parrot'} -``` - -### Declaring a set _literal_ via `{}``: - -```python -#Because sets use the same {} as dictionaries, you cannot declare an empty set with {} - ->>>empty_set = set() -set() - ->>> multiple_items = {"Triangle", "Square", "Circle"} -{'Square', 'Triangle', 'Circle'} - ->>> multiple_data_structures = {1, (3,5,9), "numbers"} -{(3, 5, 9), 1, 'numbers'} -``` - -## Concatenation - -Tuples can be _concatenated_ via the plus `+` operator, which returns a new tuple. - -```python ->>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") -("George", 5, "cat", "Tabby") -``` - -## Accessing data - -Items inside tuples can be accessed via 0-based index and _bracket notation_. - -```python -student_info = ("Alyssa", "grade 3", "female", 8 ) - -#gender is at index 2 ->>> student_gender = student_info[2] -female -``` - -## Iterating through a tuple - -Items inside tuples can be _iterated over_ in a loop using `for item in` syntax. - -## Checking membership - -The `in` operator can be used to check membership in a tuple. diff --git a/exercises/concept/sets/.meta/config.json b/exercises/concept/sets/.meta/config.json deleted file mode 100644 index 866ad0a292..0000000000 --- a/exercises/concept/sets/.meta/config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "blurb": "TODO: add blurb for sets exercise", - "icon": "meetup", - "authors": ["bethanyg"], - "files": { - "solution": ["sets.py"], - "test": ["sets_test.py"], - "exemplar": [".meta/exemplar.py"] - } -} diff --git a/exercises/concept/sets/.meta/design.md b/exercises/concept/sets/.meta/design.md deleted file mode 100644 index c94d703c6c..0000000000 --- a/exercises/concept/sets/.meta/design.md +++ /dev/null @@ -1,68 +0,0 @@ -## Goal - -The goal of this exercise is to teach the basics of [`sets`][set type] (_set type_) in Python. - - -## Learning objectives - -* understand that a set is an **unordered collection of distinct hashable objects** -* create a `set` via constructor (`set()`) and literal (`{}`) -* de-dupe a list of elements by converting a sequence type such as a `list` to a `set` type -* check for a membership of an element in a given set via `in` -* set comparison functions and set comparison operators (`=<`, `>=`, `issubset()`, `issuperset()`, etc.) -* additional set operators (`union`, `intersection`, `difference`, and `symmetric_difference`) -* add values to a given set via `add()` -* remove values from a given set via `discard()` -* iterate through a given set by using `for item in ` and `for index, item in enumerate()` -* understand that iterating through a set twince may result in a different iteration order (_sets are unordered_) - -## Out of scope - -* `frozenset()` -* `clear()` to delete all elements of a set -* check the length of a given set via `len()` -* `remove` as opposed to `discard` (_`remove` tosses a `keyerror` if the element is not present_) -* all forms/variants of `update()` -* remove (and use) a value from a given set via `pop()` -* make shallow copy(s) of a given set via `copy()` -* using additional builtins such as `sorted()`, `min()`, or `map()` with a set -* set comprehensions - -## Concepts - -* `sets` -* [`hashable`][term-hashable] objects -* `set` comparisons -* `set` operations - -## Prerequisites - -* `basics` -* `booleans` -* `comparisons` -* `dicts` -* `lists` -* `loops` - -## Resources to refer to - -* [Set Types (Python Official Docs)][set types](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) -* [Hashable (Python Official Docs Glossary)][term-hashable] -* [immutable (Python Official Docs Glossary)][term-immutable] - -### Hints - -Hints should link to the `Sets` section of the Python docs tutorial: [Sets][sets-tutorial], or equivelent resources. - - -### After - -After, the student can explore comprehension syntax, although it will be taught in separate exercises. This would also be a good time to explore set comparisons via function &/or operator, or experimenting with the `issuperset()` & `issubset()` functions. - - - -[set type]: https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/set.md -[set types]: https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset -[sets-tutorial]: https://docs.python.org/3/tutorial/datastructures.html#sets -[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable -[term-immutable]: https://docs.python.org/3/glossary.html#term-immutable \ No newline at end of file diff --git a/exercises/concept/sets/.meta/exemplar.py b/exercises/concept/sets/.meta/exemplar.py deleted file mode 100644 index 729e72a412..0000000000 --- a/exercises/concept/sets/.meta/exemplar.py +++ /dev/null @@ -1,21 +0,0 @@ -def get_coordinate(record): - return record[1] - -def convert_coordinate(coordinate): - return tuple(coordinate) - -def compare_records(azara_record, rui_record): - return convert_coordinate(azara_record[1]) in rui_record - -def create_record(azara_record, rui_record): - if compare_records(azara_record, rui_record): - return azara_record + rui_record - else: - return "not a match" - -def clean_up(combined_record_group): - - report = "" - for item in combined_record_group: - report += f"{(item[0], item[2], item[3], item[4])}\n" - return report diff --git a/exercises/concept/sets/sets.py b/exercises/concept/sets/sets.py deleted file mode 100644 index 0e21970395..0000000000 --- a/exercises/concept/sets/sets.py +++ /dev/null @@ -1,19 +0,0 @@ -def dedupe_ingredients(ingredients): - return set(ingredients) - -def create_combined_ingredients(ingredients): - combined_ingredients = set() - - for ingredient_list in ingredients: - combined_ingredients = combined_ingredients | dedupe_ingredients(ingredient_list) - - return combined_ingredients - -def check_for_(set_1, set_2): - return set_1 & set_2 - -def sets_difference(set_1, set_2): - return set_1 - set_2 - -def remove_shared_elements(set_1, set_2): - return set_1 ^ set_2 diff --git a/exercises/concept/sets/sets_test.py b/exercises/concept/sets/sets_test.py deleted file mode 100644 index b4127cda58..0000000000 --- a/exercises/concept/sets/sets_test.py +++ /dev/null @@ -1,128 +0,0 @@ -import unittest -from tuples import get_coordinate, convert_coordinate, compare_records, create_record, clean_up - - -class TuplesTest(unittest.TestCase): - - def test_get_coordinate(self): - input_data = [("Scrimshaw Whale's Tooth", '2A'), - ('Brass Spyglass', '4B'), - ('Robot Parrot', '1C'), - ('Glass Starfish', '6D'), - ('Vintage Pirate Hat', '7E'), - ('Pirate Flag', '7F'), - ('Crystal Crab', '6A'), - ('Model Ship in Large Bottle', '8A'), - ('Angry Monkey Figurine', '5B'), - ('Carved Wooden Elephant', '8C'), - ('Amethyst Octopus', '1F'), - ('Antique Glass Fishnet Float', '3D'), - ('Silver Seahorse', '4E')] - - result_data = ['2A', '4B', '1C', '6D', '7E', '7F', '6A', '8A', '5B', '8C', '1F', '3D', '4E'] - - for item, result in zip(input_data, result_data): - with self.subTest("tuple/coordinate variants", item=item, result=result): - self.assertEqual(get_coordinate(item), result) - - def test_convert_coordinate(self): - input_data = ['2A', '4B', '1C', '6D', '7E', '7F', '6A', '8A', '5B', '8C', '1F', '3D', '4E'] - result_data = [('2', 'A'), - ('4', 'B'), - ('1', 'C'), - ('6', 'D'), - ('7', 'E'), - ('7', 'F'), - ('6', 'A'), - ('8', 'A'), - ('5', 'B'), - ('8', 'C'), - ('1', 'F'), - ('3', 'D'), - ('4', 'E')] - - for item, result in zip(input_data, result_data): - with self.subTest("coordinate variants for conversion", item=item, result=result): - self.assertEqual(convert_coordinate(item), result) - - def test_compare_records(self): - input_data = [ - (("Scrimshaw Whale's Tooth", '2A'), ('Deserted Docks', ('2', 'A') ,'Blue')), - (('Brass Spyglass', '4B'), ('Abandoned Lighthouse', ('4', 'B') ,'Blue')), - (('Robot Parrot', '1C'), ('Seaside Cottages', ('1', 'C') ,'Blue')), - (('Glass Starfish', '6D'), ('Tangled Seaweed Patch', ('6', 'D'),'Orange')), - (('Vintage Pirate Hat', '7E'), ('Quiet Inlet (Island of Mystery)', ('7', 'E') ,'Orange')), - (('Amethyst Octopus', '1F'), ('Seaside Cottages', ('1', 'C') ,'Blue')), - (('Angry Monkey Figurine', '5B'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F') ,'Yellow')), - (('Antique Glass Fishnet Float', '3D'), ('Deserted Docks', ('2', 'A') ,'Blue')), - (('Brass Spyglass', '4B'), ('Spiky Rocks', ('3', 'D') ,'Yellow')), - (('Carved Wooden Elephant', '8C'), ('Abandoned Lighthouse', ('4', 'B') ,'Blue')) - ] - result_data = [True, True, True, True, True, False, False, False, False, False] - - for item, result in zip(input_data, result_data): - with self.subTest("do the coordinates match once reformatted?", item=item, result=result): - self.assertEqual(compare_records(item[0], item[1]), result) - - def test_create_record(self): - input_data=[ - (('Angry Monkey Figurine', '5B'), ('Stormy Breakwater', ('5', 'B') ,'Purple')), - (('Carved Wooden Elephant', '8C'), ('Foggy Seacave', ('8', 'C'), 'Purple')), - (('Amethyst Octopus', '1F'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F') ,'Yellow')), - (('Antique Glass Fishnet Float', '3D'), ('Spiky Rocks', ('3', 'D'),'Yellow')), - (('Silver Seahorse', '4E'), ('Hidden Spring (Island of Mystery)', ('4', 'E') ,'Yellow')), - (('Amethyst Octopus', '1F'), ('Seaside Cottages', ('1', 'C') ,'Blue')), - (('Angry Monkey Figurine', '5B'), ('Aqua Lagoon (Island of Mystery)', ('1', 'F') ,'Yellow')), - (('Antique Glass Fishnet Float', '3D'), ('Deserted Docks', ('2', 'A') ,'Blue')), - (('Brass Spyglass', '4B'), ('Spiky Rocks', ('3', 'D'),'Yellow')), - (('Carved Wooden Elephant', '8C'), ('Abandoned Lighthouse', ('4', 'B') ,'Blue')) - ] - result_data = [ - ('Angry Monkey Figurine', '5B', 'Stormy Breakwater', ('5', 'B'), 'Purple'), - ('Carved Wooden Elephant', '8C', 'Foggy Seacave', ('8', 'C'), 'Purple'), - ('Amethyst Octopus', '1F', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow'), - ('Antique Glass Fishnet Float', '3D', 'Spiky Rocks', ('3', 'D'), 'Yellow'), - ('Silver Seahorse', '4E', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow'), - 'not a match', - 'not a match', - 'not a match', - 'not a match', - 'not a match' - ] - - for item, result in zip(input_data, result_data): - with self.subTest("make record if coordinates match", item=item, result=result): - self.assertEqual(create_record(item[0], item[1]), result) - - def test_clean_up(self): - input_data = ( - ("Scrimshaw Whale's Tooth", '2A', 'Deserted Docks', ('2', 'A'), 'Blue'), - ('Brass Spyglass', '4B', 'Abandoned Lighthouse', ('4', 'B'), 'Blue'), - ('Robot Parrot', '1C', 'Seaside Cottages', ('1', 'C'), 'Blue'), - ('Glass Starfish', '6D', 'Tangled Seaweed Patch', ('6', 'D'), 'Orange'), - ('Vintage Pirate Hat', '7E', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange'), - ('Pirate Flag', '7F', 'Windswept Hilltop (Island of Mystery)', ('7', 'F'), 'Orange'), - ('Crystal Crab', '6A', 'Old Schooner', ('6', 'A'), 'Purple'), - ('Model Ship in Large Bottle', '8A', 'Harbor Managers Office', ('8', 'A'), 'Purple'), - ('Angry Monkey Figurine', '5B', 'Stormy Breakwater', ('5', 'B'), 'Purple'), - ('Carved Wooden Elephant', '8C', 'Foggy Seacave', ('8', 'C'), 'Purple'), - ('Amethyst Octopus', '1F', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow'), - ('Antique Glass Fishnet Float', '3D', 'Spiky Rocks', ('3', 'D'), 'Yellow'), - ('Silver Seahorse', '4E', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow') - ) - - result_data = """(\"Scrimshaw Whale's Tooth\", 'Deserted Docks', ('2', 'A'), 'Blue')\n\ -('Brass Spyglass', 'Abandoned Lighthouse', ('4', 'B'), 'Blue')\n\ -('Robot Parrot', 'Seaside Cottages', ('1', 'C'), 'Blue')\n\ -('Glass Starfish', 'Tangled Seaweed Patch', ('6', 'D'), 'Orange')\n\ -('Vintage Pirate Hat', 'Quiet Inlet (Island of Mystery)', ('7', 'E'), 'Orange')\n\ -('Pirate Flag', 'Windswept Hilltop (Island of Mystery)', ('7', 'F'), 'Orange')\n\ -('Crystal Crab', 'Old Schooner', ('6', 'A'), 'Purple')\n\ -('Model Ship in Large Bottle', 'Harbor Managers Office', ('8', 'A'), 'Purple')\n\ -('Angry Monkey Figurine', 'Stormy Breakwater', ('5', 'B'), 'Purple')\n\ -('Carved Wooden Elephant', 'Foggy Seacave', ('8', 'C'), 'Purple')\n\ -('Amethyst Octopus', 'Aqua Lagoon (Island of Mystery)', ('1', 'F'), 'Yellow')\n\ -('Antique Glass Fishnet Float', 'Spiky Rocks', ('3', 'D'), 'Yellow')\n\ -('Silver Seahorse', 'Hidden Spring (Island of Mystery)', ('4', 'E'), 'Yellow')\n""" - - self.assertEqual(clean_up(input_data), result_data) From 0879531b38ad08a88d7c74865844a63d6459f12c Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:54:15 -0700 Subject: [PATCH 06/34] Renamed after to deprecated_after. --- .../concept/cater-waiter/.docs/{after.md => deprecated_after.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/cater-waiter/.docs/{after.md => deprecated_after.md} (100%) diff --git a/exercises/concept/cater-waiter/.docs/after.md b/exercises/concept/cater-waiter/.docs/deprecated_after.md similarity index 100% rename from exercises/concept/cater-waiter/.docs/after.md rename to exercises/concept/cater-waiter/.docs/deprecated_after.md From d437e50a5a17ce2f42a87c7793e519cd773726b7 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Sat, 21 Aug 2021 11:56:42 -0700 Subject: [PATCH 07/34] Ran prettier. --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index d7f351d09c..cc4351ad0d 100644 --- a/config.json +++ b/config.json @@ -173,7 +173,7 @@ "name": "Cater Waiter", "uuid": "922f8d2d-87ec-4681-9654-4e0a36a558d4", "concepts": ["sets"], - "prerequisites": ["basics", "dicts", "lists", "loops", "tuples"], + "prerequisites": ["basics", "dicts", "lists", "loops", "tuples"], "status": "beta" } ], From 5a67f4393be1ecfbcfbfad4ce7a75108a55b33a1 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 14:24:43 -0700 Subject: [PATCH 08/34] Added editor field to data py for test runner CI. --- bin/data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/data.py b/bin/data.py index f81a3d2434..7ca0c99a34 100644 --- a/bin/data.py +++ b/bin/data.py @@ -104,6 +104,7 @@ class ExerciseFiles: solution: List[str] test: List[str] exemplar: List[str] = None + editor: List[str] = None # practice exercises are different example: List[str] = None From c3dda695dd300f1e58cd79ed7f3ea84f6cb84d89 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 14:39:10 -0700 Subject: [PATCH 09/34] Changed editor to not have a default value in the dataclass. --- bin/data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/data.py b/bin/data.py index 7ca0c99a34..13bb606ab7 100644 --- a/bin/data.py +++ b/bin/data.py @@ -103,8 +103,9 @@ class ExerciseFiles: solution: List[str] test: List[str] + editor: List[str] exemplar: List[str] = None - editor: List[str] = None + # practice exercises are different example: List[str] = None From e0d61cbd4e447361f19341a95c59658203505aeb Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 14:41:46 -0700 Subject: [PATCH 10/34] Reverting to default arugment for dataclass. --- bin/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/data.py b/bin/data.py index 13bb606ab7..26af4e7450 100644 --- a/bin/data.py +++ b/bin/data.py @@ -103,7 +103,7 @@ class ExerciseFiles: solution: List[str] test: List[str] - editor: List[str] + editor: List[str] = None exemplar: List[str] = None From ef11fbf74683a9d2c765fb408fde30864d88c299 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 14:56:35 -0700 Subject: [PATCH 11/34] Added editor files into the list of files to copy to the runner. --- bin/test_exercises.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 285ab1bd92..180fb5beb8 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -46,9 +46,11 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: if exercise_config is not None: solution_files = exercise_config.files.solution exemplar_files = exercise_config.files.exemplar + helper_files = exercise_config.files.editor else: solution_files = [] exemplar_files = [] + helper_files = [] if not solution_files: solution_files.append(exercise.solution_stub.name) solution_files = [exercise.path / s for s in solution_files] From fad93d7e5d9d6f72c80d3a338352db386540f815 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:00:36 -0700 Subject: [PATCH 12/34] Added editor files into the list of files to copy to the runner. AGAIN. --- bin/test_exercises.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 180fb5beb8..83daa43e77 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -70,8 +70,10 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = None): if exercise_config is not None: test_files = exercise_config.files.test + helper_files = exercise_config.files.editor else: test_files = [] + helper_files = [] if not test_files: test_files.append(exercise.test_file.name) for test_file_name in test_files: From 55e779de5cfe1ac6a4f1727ab17f06064b3f3fa4 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:20:29 -0700 Subject: [PATCH 13/34] Updated property for helper_files. --- bin/data.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/data.py b/bin/data.py index 26af4e7450..fa45d171a8 100644 --- a/bin/data.py +++ b/bin/data.py @@ -193,6 +193,17 @@ def solution_stub(self): None, ) + @property + def helper_files(self): + return next( + ( + p + for p in self.path.glob("*.py") + if p.name.endswith("_data.py") and p.name != "example.py" + ), + None, + ) + @property def test_file(self): return next(self.path.glob("*_test.py"), None) From 8c8a5917ddc36f7a66b2b706353dbb2788d29b49 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:21:09 -0700 Subject: [PATCH 14/34] renamed sets_categories to sets_catigories_data, to help with helper file naming. --- exercises/concept/cater-waiter/sets.py | 22 ++++++++--------- ..._categories.py => sets_categories_data.py} | 0 exercises/concept/cater-waiter/sets_test.py | 24 +++++++++---------- .../concept/cater-waiter/sets_test_data.py | 10 ++++---- 4 files changed, 28 insertions(+), 28 deletions(-) rename exercises/concept/cater-waiter/{sets_categories.py => sets_categories_data.py} (100%) diff --git a/exercises/concept/cater-waiter/sets.py b/exercises/concept/cater-waiter/sets.py index e0ae31bf1d..727bd14556 100644 --- a/exercises/concept/cater-waiter/sets.py +++ b/exercises/concept/cater-waiter/sets.py @@ -1,14 +1,14 @@ -from sets_categories import (VEGAN, - VEGETARIAN, - KETO, PALEO, - OMNIVORE, - ALCOHOLS, - SPECIAL_INGREDIENTS, - VEGAN_INTERSECTIONS, - VEGETARIAN_INTERSECTIONS, - PALEO_INTERSECTIONS, - KETO_INTERSECTIONS, - OMNIVORE_INTERSECTIONS) +from sets_categories_data import (VEGAN, + VEGETARIAN, + KETO, PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) def clean_ingredients(dish_name, dish_ingredients): diff --git a/exercises/concept/cater-waiter/sets_categories.py b/exercises/concept/cater-waiter/sets_categories_data.py similarity index 100% rename from exercises/concept/cater-waiter/sets_categories.py rename to exercises/concept/cater-waiter/sets_categories_data.py diff --git a/exercises/concept/cater-waiter/sets_test.py b/exercises/concept/cater-waiter/sets_test.py index 9767df33a9..033c3bd49e 100644 --- a/exercises/concept/cater-waiter/sets_test.py +++ b/exercises/concept/cater-waiter/sets_test.py @@ -1,17 +1,17 @@ import unittest import pytest -from sets_categories import (VEGAN, - VEGETARIAN, - KETO, - PALEO, - OMNIVORE, - ALCOHOLS, - SPECIAL_INGREDIENTS, - VEGAN_INTERSECTIONS, - VEGETARIAN_INTERSECTIONS, - PALEO_INTERSECTIONS, - KETO_INTERSECTIONS, - OMNIVORE_INTERSECTIONS) +from sets_categories_data import (VEGAN, + VEGETARIAN, + KETO, + PALEO, + OMNIVORE, + ALCOHOLS, + SPECIAL_INGREDIENTS, + VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) from sets_test_data import (recipes_with_duplicates, recipes_without_duplicates, diff --git a/exercises/concept/cater-waiter/sets_test_data.py b/exercises/concept/cater-waiter/sets_test_data.py index 11881ed704..3edee21d5b 100644 --- a/exercises/concept/cater-waiter/sets_test_data.py +++ b/exercises/concept/cater-waiter/sets_test_data.py @@ -1,8 +1,8 @@ -from sets_categories import (VEGAN_INTERSECTIONS, - VEGETARIAN_INTERSECTIONS, - PALEO_INTERSECTIONS, - KETO_INTERSECTIONS, - OMNIVORE_INTERSECTIONS) +from sets_categories_data import (VEGAN_INTERSECTIONS, + VEGETARIAN_INTERSECTIONS, + PALEO_INTERSECTIONS, + KETO_INTERSECTIONS, + OMNIVORE_INTERSECTIONS) ################################### From 51521a3dd5f70a1f6d84fa26c2761b017b2f3172 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:28:47 -0700 Subject: [PATCH 15/34] Changed categories to categories_data in exercise config. --- exercises/concept/cater-waiter/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/cater-waiter/.meta/config.json b/exercises/concept/cater-waiter/.meta/config.json index 57cd451eda..949146f649 100644 --- a/exercises/concept/cater-waiter/.meta/config.json +++ b/exercises/concept/cater-waiter/.meta/config.json @@ -6,6 +6,6 @@ "solution": ["sets.py"], "test": ["sets_test.py"], "exemplar": [".meta/exemplar.py"], - "editor": ["sets_test_data.py", "sets_categories.py"] + "editor": ["sets_test_data.py", "sets_categories_data.py"] } } From 70d65777cedd9ff0806a76d2c960fb63d33ce57a Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:32:32 -0700 Subject: [PATCH 16/34] Tried different strategy for helper_files property. --- bin/data.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/bin/data.py b/bin/data.py index fa45d171a8..908abc8e2e 100644 --- a/bin/data.py +++ b/bin/data.py @@ -195,14 +195,7 @@ def solution_stub(self): @property def helper_files(self): - return next( - ( - p - for p in self.path.glob("*.py") - if p.name.endswith("_data.py") and p.name != "example.py" - ), - None, - ) + return next(self.path.glob("*_data.py"), None) @property def test_file(self): From 501159460f38cb81ce475c061d49dffacddbb0db Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:37:29 -0700 Subject: [PATCH 17/34] Removed helper files from solutions copy, hope this stops the test colllection error. --- bin/test_exercises.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 83daa43e77..9fc437df38 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -46,11 +46,9 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: if exercise_config is not None: solution_files = exercise_config.files.solution exemplar_files = exercise_config.files.exemplar - helper_files = exercise_config.files.editor else: solution_files = [] exemplar_files = [] - helper_files = [] if not solution_files: solution_files.append(exercise.solution_stub.name) solution_files = [exercise.path / s for s in solution_files] From 4710b8ee7206b5aad57156a607fcef791379d79b Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:46:31 -0700 Subject: [PATCH 18/34] More attempts at a fix for the copy issue. --- bin/data.py | 1 + bin/test_exercises.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/bin/data.py b/bin/data.py index 908abc8e2e..daca72db2b 100644 --- a/bin/data.py +++ b/bin/data.py @@ -280,6 +280,7 @@ class FilePatterns: solution: List[str] test: List[str] example: List[str] + editor: List[str] exemplar: List[str] diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 9fc437df38..83daa43e77 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -46,9 +46,11 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: if exercise_config is not None: solution_files = exercise_config.files.solution exemplar_files = exercise_config.files.exemplar + helper_files = exercise_config.files.editor else: solution_files = [] exemplar_files = [] + helper_files = [] if not solution_files: solution_files.append(exercise.solution_stub.name) solution_files = [exercise.path / s for s in solution_files] From 9972301fea1745424eded61b2b3980c6d65263d8 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 15:54:53 -0700 Subject: [PATCH 19/34] Added None default param for editor file patterns. --- bin/data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/data.py b/bin/data.py index daca72db2b..d4d47a6e95 100644 --- a/bin/data.py +++ b/bin/data.py @@ -280,7 +280,7 @@ class FilePatterns: solution: List[str] test: List[str] example: List[str] - editor: List[str] + editor: List[str] = None exemplar: List[str] From aad9997624037596537f94f01bd76d43f6724281 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 16:08:18 -0700 Subject: [PATCH 20/34] moved default argument to below positional argument. I hate everything, and everyone. --- bin/data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/data.py b/bin/data.py index d4d47a6e95..df54bf6b1f 100644 --- a/bin/data.py +++ b/bin/data.py @@ -280,8 +280,9 @@ class FilePatterns: solution: List[str] test: List[str] example: List[str] - editor: List[str] = None exemplar: List[str] + editor: List[str] = None + @dataclass From c525fbbc49e2cf40008b061fb6c5dad61ff012b8 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 16:24:10 -0700 Subject: [PATCH 21/34] And another edit because I am stupidly stubborn. --- bin/test_exercises.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 83daa43e77..bc3df85a59 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -80,6 +80,9 @@ def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = Non test_file = exercise.path / test_file_name test_file_out = workdir / test_file_name copy_file(test_file, test_file_out, strip_skips=(exercise.slug not in ALLOW_SKIP)) + for helper_file_name in helper_files: + helper_file = exercise.path / helper_file_name + copy_file(helper_file, strip_skips=(exercise.slug not in ALLOW_SKIP)) def copy_exercise_files(exercise: ExerciseInfo, workdir: Path): From 3e94010fd6a4fabea0750a3697f9d7855e763ac2 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 18:19:27 -0700 Subject: [PATCH 22/34] Added None check for helper_file copy. --- bin/test_exercises.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index bc3df85a59..c84ac6933c 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -76,13 +76,16 @@ def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = Non helper_files = [] if not test_files: test_files.append(exercise.test_file.name) + for test_file_name in test_files: test_file = exercise.path / test_file_name test_file_out = workdir / test_file_name copy_file(test_file, test_file_out, strip_skips=(exercise.slug not in ALLOW_SKIP)) - for helper_file_name in helper_files: - helper_file = exercise.path / helper_file_name - copy_file(helper_file, strip_skips=(exercise.slug not in ALLOW_SKIP)) + + if helper_files is not None: + for helper_file_name in helper_files: + helper_file = exercise.path / helper_file_name + copy_file(helper_file, strip_skips=(exercise.slug not in ALLOW_SKIP)) def copy_exercise_files(exercise: ExerciseInfo, workdir: Path): From 417933956cae098d2617167e37c9056498f618cf Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 18:26:44 -0700 Subject: [PATCH 23/34] Added dst. --- bin/test_exercises.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index c84ac6933c..46a060b21d 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -85,8 +85,8 @@ def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = Non if helper_files is not None: for helper_file_name in helper_files: helper_file = exercise.path / helper_file_name - copy_file(helper_file, strip_skips=(exercise.slug not in ALLOW_SKIP)) - + dst = workdir / helper_file.relative_to(exercise.path) + copy_file(helper_file, dst) def copy_exercise_files(exercise: ExerciseInfo, workdir: Path): exercise_config = None From 760eb826afa1e37be3829b30b7161c53fe84bcce Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:00:41 -0700 Subject: [PATCH 24/34] Added another missing copy for exercise files. --- bin/test_exercises.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 46a060b21d..22280117e9 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -51,12 +51,15 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: solution_files = [] exemplar_files = [] helper_files = [] + if not solution_files: solution_files.append(exercise.solution_stub.name) - solution_files = [exercise.path / s for s in solution_files] + solution_files = [exercise.path / file for file in solution_files] + if not exemplar_files: exemplar_files.append(exercise.exemplar_file.relative_to(exercise.path)) - exemplar_files = [exercise.path / e for e in exemplar_files] + exemplar_files = [exercise.path / exercise for exercise in exemplar_files] + for solution_file, exemplar_file in zip_longest(solution_files, exemplar_files): if solution_file is None: copy_file(exemplar_file, workdir / exemplar_file.name) @@ -66,6 +69,11 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: dst = workdir / solution_file.relative_to(exercise.path) copy_file(exemplar_file, dst) + helper_files = [exercise.path / helper for helper in helper_files] + for helper_file in helper_files: + dist = wordir / helper_file.relative_to(exercise.path) + copy_file(helper_file, dist) + def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = None): if exercise_config is not None: From eb6241d46adc286e9ed2d16d251971859b8aa110 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:05:39 -0700 Subject: [PATCH 25/34] Typos are fun. Really fun. --- bin/test_exercises.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index 22280117e9..ff05e7be24 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -71,7 +71,7 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: helper_files = [exercise.path / helper for helper in helper_files] for helper_file in helper_files: - dist = wordir / helper_file.relative_to(exercise.path) + dist = workdir / helper_file.relative_to(exercise.path) copy_file(helper_file, dist) From 8101915bd01a665e67af50e7dbfeec8c8564ef33 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:10:34 -0700 Subject: [PATCH 26/34] Renamed variables in comprehensions. --- bin/test_exercises.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index ff05e7be24..f6e6805b08 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -54,11 +54,10 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: if not solution_files: solution_files.append(exercise.solution_stub.name) - solution_files = [exercise.path / file for file in solution_files] - + solution_files = [exercise.path / s for s in solution_files] if not exemplar_files: exemplar_files.append(exercise.exemplar_file.relative_to(exercise.path)) - exemplar_files = [exercise.path / exercise for exercise in exemplar_files] + exemplar_files = [exercise.path / e for e in exemplar_files] for solution_file, exemplar_file in zip_longest(solution_files, exemplar_files): if solution_file is None: @@ -69,7 +68,7 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: dst = workdir / solution_file.relative_to(exercise.path) copy_file(exemplar_file, dst) - helper_files = [exercise.path / helper for helper in helper_files] + helper_files = [exercise.path / h for h in helper_files] for helper_file in helper_files: dist = workdir / helper_file.relative_to(exercise.path) copy_file(helper_file, dist) From cd57fd2b296376d7172019e74a56b6685ecf35f9 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:13:05 -0700 Subject: [PATCH 27/34] None check. --- bin/test_exercises.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/test_exercises.py b/bin/test_exercises.py index f6e6805b08..bfcf03ac18 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -68,10 +68,11 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: dst = workdir / solution_file.relative_to(exercise.path) copy_file(exemplar_file, dst) - helper_files = [exercise.path / h for h in helper_files] - for helper_file in helper_files: - dist = workdir / helper_file.relative_to(exercise.path) - copy_file(helper_file, dist) + if helper_files: + helper_files = [exercise.path / h for h in helper_files] + for helper_file in helper_files: + dist = workdir / helper_file.relative_to(exercise.path) + copy_file(helper_file, dist) def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = None): From 788ff4f8e13a3fe7c66cf88dd53786b8c7e50d40 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:20:57 -0700 Subject: [PATCH 28/34] Test by adding data files to solutiona and test arrays. --- exercises/concept/cater-waiter/.meta/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/cater-waiter/.meta/config.json b/exercises/concept/cater-waiter/.meta/config.json index 949146f649..76e1990dd7 100644 --- a/exercises/concept/cater-waiter/.meta/config.json +++ b/exercises/concept/cater-waiter/.meta/config.json @@ -3,8 +3,8 @@ "icon": "meetup", "authors": ["bethanyg"], "files": { - "solution": ["sets.py"], - "test": ["sets_test.py"], + "solution": ["sets.py", "sets_categories_data.py"], + "test": ["sets_test.py","sets_test_data.py", "sets_categories_data.py"], "exemplar": [".meta/exemplar.py"], "editor": ["sets_test_data.py", "sets_categories_data.py"] } From f84568f2c24b0f2c121aac04a6716ba0c5a04c87 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 19:40:56 -0700 Subject: [PATCH 29/34] Revert config changes. --- exercises/concept/cater-waiter/.meta/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/cater-waiter/.meta/config.json b/exercises/concept/cater-waiter/.meta/config.json index 76e1990dd7..949146f649 100644 --- a/exercises/concept/cater-waiter/.meta/config.json +++ b/exercises/concept/cater-waiter/.meta/config.json @@ -3,8 +3,8 @@ "icon": "meetup", "authors": ["bethanyg"], "files": { - "solution": ["sets.py", "sets_categories_data.py"], - "test": ["sets_test.py","sets_test_data.py", "sets_categories_data.py"], + "solution": ["sets.py"], + "test": ["sets_test.py"], "exemplar": [".meta/exemplar.py"], "editor": ["sets_test_data.py", "sets_categories_data.py"] } From a1412b7ceec588c64fd16d96ae3b28e687bbd205 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 23:03:25 -0700 Subject: [PATCH 30/34] Cleaned up helper_file references and file copy debug statements. --- bin/data.py | 2 +- bin/test_exercises.py | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/bin/data.py b/bin/data.py index df54bf6b1f..626e462bc3 100644 --- a/bin/data.py +++ b/bin/data.py @@ -194,7 +194,7 @@ def solution_stub(self): ) @property - def helper_files(self): + def helper_file(self): return next(self.path.glob("*_data.py"), None) @property diff --git a/bin/test_exercises.py b/bin/test_exercises.py index bfcf03ac18..0b6e727b86 100755 --- a/bin/test_exercises.py +++ b/bin/test_exercises.py @@ -52,6 +52,12 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: exemplar_files = [] helper_files = [] + if helper_files: + helper_files = [exercise.path / h for h in helper_files] + for helper_file in helper_files: + dst = workdir / helper_file.relative_to(exercise.path) + copy_file(helper_file, dst) + if not solution_files: solution_files.append(exercise.solution_stub.name) solution_files = [exercise.path / s for s in solution_files] @@ -68,12 +74,6 @@ def copy_solution_files(exercise: ExerciseInfo, workdir: Path, exercise_config: dst = workdir / solution_file.relative_to(exercise.path) copy_file(exemplar_file, dst) - if helper_files: - helper_files = [exercise.path / h for h in helper_files] - for helper_file in helper_files: - dist = workdir / helper_file.relative_to(exercise.path) - copy_file(helper_file, dist) - def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = None): if exercise_config is not None: @@ -82,6 +82,13 @@ def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = Non else: test_files = [] helper_files = [] + + if helper_files: + for helper_file_name in helper_files: + helper_file = exercise.path / helper_file_name + helper_file_out = workdir / helper_file_name + copy_file(helper_file, helper_file_out, strip_skips=(exercise.slug not in ALLOW_SKIP)) + if not test_files: test_files.append(exercise.test_file.name) @@ -90,11 +97,6 @@ def copy_test_files(exercise: ExerciseInfo, workdir: Path, exercise_config = Non test_file_out = workdir / test_file_name copy_file(test_file, test_file_out, strip_skips=(exercise.slug not in ALLOW_SKIP)) - if helper_files is not None: - for helper_file_name in helper_files: - helper_file = exercise.path / helper_file_name - dst = workdir / helper_file.relative_to(exercise.path) - copy_file(helper_file, dst) def copy_exercise_files(exercise: ExerciseInfo, workdir: Path): exercise_config = None From 77f7366f33d2f2e4e4dff6fc1c052efa554b6e8a Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 23:03:54 -0700 Subject: [PATCH 31/34] Corrected mis-named import statement. --- exercises/concept/cater-waiter/.meta/exemplar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/cater-waiter/.meta/exemplar.py b/exercises/concept/cater-waiter/.meta/exemplar.py index 18571636e9..3d17fc12c2 100644 --- a/exercises/concept/cater-waiter/.meta/exemplar.py +++ b/exercises/concept/cater-waiter/.meta/exemplar.py @@ -1,4 +1,4 @@ -from sets_categories import (VEGAN, +from sets_categories_data import (VEGAN, VEGETARIAN, KETO, PALEO, From d80fdf1ebd16790d8e2e691e6469cb755522b5a3 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 23:04:31 -0700 Subject: [PATCH 32/34] Cleaned up test data at bottom of file. --- .../cater-waiter/sets_categories_data.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/exercises/concept/cater-waiter/sets_categories_data.py b/exercises/concept/cater-waiter/sets_categories_data.py index b23a91f798..52d00b1788 100644 --- a/exercises/concept/cater-waiter/sets_categories_data.py +++ b/exercises/concept/cater-waiter/sets_categories_data.py @@ -208,20 +208,3 @@ 'cumin powder', 'onion', 'water', 'chickpea flour', 'coriander seeds', 'turmeric powder', 'hing', 'coriander powder', 'cinnamon powder', 'cilantro', 'garlic'} ] - -one = {'salt', 'breadcrumbs', 'water', 'flour', 'celeriac', 'chickpea flour', - 'soy sauce', 'parsley','sunflower oil', 'lemon', 'black pepper'} - -two = {'cornstarch', 'salt', 'vegetable oil', 'sugar', 'vegetable stock', - 'water', 'tofu', 'soy sauce','lemon zest', 'lemon juice', - 'black pepper','ginger', 'garlic'} - -three = {'salt', 'mixed herbs', 'silken tofu', 'smoked tofu', 'nutritional yeast', - 'turmeric', 'soy sauce','garlic', 'lemon juice', 'olive oil', - 'black pepper','spaghetti'} - -four = {'salt', 'mushrooms', 'sugar', 'barley malt', 'nutritional yeast','fresh basil', - 'olive oil','honey', 'yeast', 'red onion', 'bell pepper','cashews', 'oregano', - 'rosemary', 'garlic powder','tomatoes', 'water','flour', 'red pepper flakes', 'garlic'} - -(one & two | one & three | one & four | two & three | two & four | three & four) \ No newline at end of file From ec29da2a14be9996b4f7a78c8a20f43837dfa226 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 23:05:05 -0700 Subject: [PATCH 33/34] restored stub file and docstrings. --- exercises/concept/cater-waiter/sets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/concept/cater-waiter/sets.py b/exercises/concept/cater-waiter/sets.py index 727bd14556..102cd25c53 100644 --- a/exercises/concept/cater-waiter/sets.py +++ b/exercises/concept/cater-waiter/sets.py @@ -1,6 +1,7 @@ from sets_categories_data import (VEGAN, VEGETARIAN, - KETO, PALEO, + KETO, + PALEO, OMNIVORE, ALCOHOLS, SPECIAL_INGREDIENTS, From 17523c65a3daed0e93d0355fb3e282a0f2221267 Mon Sep 17 00:00:00 2001 From: BethanyG Date: Wed, 25 Aug 2021 23:06:01 -0700 Subject: [PATCH 34/34] Removed exemplar import and re-orders sets file import to be near top. --- exercises/concept/cater-waiter/sets_test.py | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/exercises/concept/cater-waiter/sets_test.py b/exercises/concept/cater-waiter/sets_test.py index 033c3bd49e..39af0cb7f3 100644 --- a/exercises/concept/cater-waiter/sets_test.py +++ b/exercises/concept/cater-waiter/sets_test.py @@ -1,9 +1,18 @@ import unittest import pytest + +from sets import (clean_ingredients, + check_drinks, + categorize_dish, + tag_special_ingredients, + compile_ingredients, + separate_appetizers, + singleton_ingredients) + + from sets_categories_data import (VEGAN, VEGETARIAN, - KETO, - PALEO, + KETO, PALEO, OMNIVORE, ALCOHOLS, SPECIAL_INGREDIENTS, @@ -27,15 +36,6 @@ singletons) -from exemplar import (clean_ingredients, - check_drinks, - categorize_dish, - tag_special_ingredients, - compile_ingredients, - separate_appetizers, - singleton_ingredients,) - - class SetsTest(unittest.TestCase): @pytest.mark.task(taskno=1)