Implement a RecipeManager class for a digital recipe manager. The task is progressive (Levels 1–4). You can assume a single-process in-memory implementation. Correctness matters; efficiency is not required. Unless otherwise stated, all string comparisons for recipe names and ingredient matching are case-insensitive.
A recipe has:
recipe_id
: formatted as
"recipe" + N
, where
N
is a sequential integer starting from 1 in creation order.
name
: unique across all recipes (case-insensitive).
ingredients
: list of strings (keep original order).
steps
: list of strings (keep original order).
When returning a recipe, represent it as:
[name, ingredients_as_string, steps_as_string]
ingredients_as_string
is the ingredients joined by
","
(comma separator), and similarly for
steps_as_string
.
If a method returns a list of recipe IDs, they are strings like "recipe1", "recipe2", etc.
Implement:
add_recipe(self, name: str, ingredients: list[str], steps: list[str]) -> str | None
recipe_id
.
None
.
get_recipe(self, recipe_id: str) -> list[str]
[name, ingredients_as_string, steps_as_string]
for the recipe.
[]
.
update_recipe(self, recipe_id: str, name: str, ingredients: list[str], steps: list[str]) -> bool
True
if successful.
False
if the recipe does not exist, or if the new name conflicts with another existing recipe name (case-insensitive).
delete_recipe(self, recipe_id: str) -> bool
True
if it existed and was deleted; otherwise
False
.
Implement:
search_recipes_by_ingredient(self, ingredient: str) -> list[str]
recipe_id
ascending (tie-breaker)
list_recipes(self, sort_by: str) -> list[str]
sort_by
, where
sort_by
is either:
"name"
: lexicographic ascending by recipe name; tie-breaker
recipe_id
ascending
"ingredient_count"
: ascending by number of ingredients; tie-breaker
recipe_id
ascending
sort_by
is invalid, default to sorting by
"name"
.
Introduce users.
add_user(self, user_id: str) -> bool
True
if added;
False
if the user already exists.
edit_recipe(self, user_id: str, recipe_id: str, new_name: str, new_ingredients: list[str], new_steps: list[str]) -> bool
True
on success.
False
if the user does not exist, the recipe does not exist, or the new name conflicts with another recipe name.
Add version control for recipes.
Definitions:
add_recipe
have
no version history
until the first successful
edit_recipe
or
update_recipe
.
edit_recipe
or
update_recipe
creates a new version entry.
<version>:<name>:<ingredients_as_string>:<steps_as_string>:<last_edited_by>
edit_recipe
,
<last_edited_by>
is the
user_id
.
update_recipe
,
<last_edited_by>
is the literal string
"system"
.
Implement:
version_recipe(self, recipe_id: str) -> list[str]
[]
if the recipe does not exist or if it was never edited/updated (i.e., no version history).
rollback_recipe(self, recipe_id: str, version: int) -> bool
version
.
"rollback"
.
True
if successful.
False
if the recipe does not exist, the requested version does not exist, or if rolling back would cause a name conflict with another existing recipe (case-insensitive).