Руководство местной кофейни для программистов под названием Java-0x00
решило модернизировать систему заказа кофе.
Для этого им требуется реализовать функцию order
, которая принимает список предпочтений посетителя в порядке «убывания желания».
Согласно положению, каждый напиток в кофейне строго определён рецептом:
- Эспрессо готовится из: 1 порции кофейных зерен.
- Капучино готовится из: 1 порции кофейных зерен и 3 порций молока.
- Макиато готовится из: 2 порций кофейных зерен и 1 порции молока.
- Кофе по-венски готовится из: 1 порции кофейных зерен и 2 порций взбитых сливок.
- Латте Макиато готовится из: 1 порции кофейных зерен, 2 порций молока и 1 порции взбитых сливок.
- Кон Панна готовится из: 1 порции кофейных зерен и 1 порции взбитых сливок.
В глобальной переменной in_stock
содержится словарь, описывающий ингредиенты в наличии. Ключи словаря: coffee
, cream
, milk
.
Функция должна вернуть:
- название напитка, который будет приготовлен;
- сообщение «К сожалению, не можем предложить Вам напиток», если ни одно из предпочтений не может быть приготовлено.
Если заказ, может быть совершён, количество доступных ингредиентов должно соответствующим образом уменьшиться.
Примечание
В решении не должно быть вызовов требуемых функций.
Пример
Ввод
in_stock = {"coffee": 1, "milk": 2, "cream": 3}
print(order("Эспрессо", "Капучино", "Макиато", "Кофе по-венски", "Латте Макиато", "Кон Панна"))
print(order("Эспрессо", "Капучино", "Макиато", "Кофе по-венски", "Латте Макиато", "Кон Панна"))
Вывод
Эспрессо
К сожалению, не можем предложить Вам напиток
Ввод
in_stock = {"coffee": 4, "milk": 4, "cream": 0}
print(order("Капучино", "Макиато", "Эспрессо"))
print(order("Капучино", "Макиато", "Эспрессо"))
print(order("Капучино", "Макиато", "Эспрессо"))
Вывод
Капучино
Макиато
Эспрессо
Решение
Очень хорошая задача на применение словарей. Применение глобальных переменных не так оправдано, но мы в этом разделе изучаем именно их, а значит, пусть будут глобальные переменные.
Формируем словарь рецептов. Будьте на этом этапе особенно внимательны. 90% вопросов о неработоспособностью программы связаны именно с ошибками в словаре.
Каждый вызов запускаем проверку – всех ли ингредиентов хватает, чтобы приготовить напиток. Если да, то возвращаем название напитка, если нет, то сообщение с извинениями.
Для того, чтобы проверить хватает ли нам ингредиентов, достаточно СНАЧАЛА проверить все ключи словаря рецепта, а потом, и только в случае успеха уменьшить значения соответствующих ингредиентов на складе.
На этом можно было бы и закончить, но представленный алгоритм не учитывает одну простую вещь – а что, если в рецептах есть ингредиент, которого нет в списке ингредиентов на складе? Первые три решения выдадут ошибку, что конечно же, неправильно. Решить проблему может простая проверка – прежде чем проверять хватает ли данного ингредиента на складе, можно проверить есть ли он там вообще в списке ингредиентов. Сделать это можно прямо в конструкции которая проверяет достаточность ингредиентов.
Посмотреть код
Решение
RECIPES = {
"Эспрессо": {"coffee": 1},
"Капучино": {"coffee": 1, "milk": 3},
"Макиато": {"coffee": 2, "milk": 1},
"Кофе по-венски": {"coffee": 1, "cream": 2},
"Латте Макиато": {"coffee": 1, "milk": 2, "cream": 1},
"Кон Панна": {"coffee": 1, "cream": 1},
}
in_stock = {}
def order(*drinks):
global in_stock
for drink in drinks:
for ingredient in RECIPES[drink]:
if RECIPES[drink].get(ingredient, 0) > in_stock[ingredient]:
break
else:
for ingredient in RECIPES[drink]:
in_stock[ingredient] -= RECIPES[drink][ingredient]
return drink
if in_stock:
return "К сожалению, не можем предложить Вам напиток"
Решение
RECIPES = {
'Эспрессо': {'coffee': 1},
'Капучино': {"coffee": 1, "milk": 3},
'Макиато': {"coffee": 2, "milk": 1},
'Кофе по-венски': {"coffee": 1, "cream": 2},
'Латте Макиато': {"coffee": 1, "milk": 2, "cream": 1},
'Кон Панна': {"coffee": 1, "cream": 1},
}
in_stock = {}
def is_ingredients_enough(drink):
global RECIPES, in_stock
return all(
ingredient in in_stock and RECIPES[drink][ingredient] <= in_stock[ingredient] for ingredient in RECIPES[drink]
) # noqa
def order(*drinks):
global RECIPES, in_stock
for drink in drinks:
if is_ingredients_enough(drink):
for ingredient, amount in RECIPES[drink].items():
in_stock[ingredient] -= amount
return drink
return 'К сожалению, не можем предложить Вам напиток'
Решение
RECIPES = {
'Эспрессо': {'coffee': 1},
'Капучино': {"coffee": 1, "milk": 3},
'Макиато': {"coffee": 2, "milk": 1},
'Кофе по-венски': {"coffee": 1, "cream": 2},
'Латте Макиато': {"coffee": 1, "milk": 2, "cream": 1},
'Кон Панна': {"coffee": 1, "cream": 1}
}
in_stock = {}
def order(*drinks):
global in_stock, RECIPES
for drink in drinks:
if all(RECIPES[drink][ingredient] <= in_stock[ingredient] for ingredient in RECIPES[drink]):
for ingredient, amount in RECIPES[drink].items():
in_stock[ingredient] -= amount
return drink
return "К сожалению, не можем предложить Вам напиток"
Решение
# Полное с точки зрения логики, но избыточное с точки зрения тестов Яндекса решение
RECIPES = {
'Эспрессо': {'coffee': 1},
'Капучино': {"coffee": 1, "milk": 3},
'Макиато': {"coffee": 2, "milk": 1},
'Кофе по-венски': {"coffee": 1, "cream": 2},
'Латте Макиато': {"coffee": 1, "milk": 2, "cream": 1},
'Кон Панна': {"coffee": 1, "cream": 1}
}
in_stock = {}
def order(*drinks):
global in_stock, RECIPES
for drink in drinks:
if all(ingredient in in_stock and RECIPES[drink][ingredient] <= in_stock[ingredient] for ingredient in RECIPES[drink]): # noqa
for ingredient, amount in RECIPES[drink].items():
in_stock[ingredient] -= amount
return drink
return "К сожалению, не можем предложить Вам напиток"
К сожалению я понял условие так, что нужно использовать только функцию, и нельзя задавать “дополнительные” глобальные переменные, а задавать словарь для проверки в самой функции тоже нельзя (или не красиво). В связи с чем, вот такое решение…
def order(*name_drink):
global in_stock
flag = True
for name in name_drink:
match name:
case ‘Эспрессо’:
if in_stock[“coffee”] >= 1:
in_stock[“coffee”] -= 1
return name
case ‘Капучино’:
if in_stock[“coffee”] >= 1 and in_stock[“milk”] >= 3:
in_stock[“coffee”] -= 1
in_stock[“milk”] -= 3
return name
case ‘Макиато’:
if in_stock[“coffee”] >= 2 and in_stock[“milk”] >= 1:
in_stock[“coffee”] -= 2
in_stock[“milk”] -= 1
return name
case ‘Кофе по-венски’:
if in_stock[“coffee”] >= 1 and in_stock[“cream”] >= 2:
in_stock[“coffee”] -= 1
in_stock[“cream”] -= 2
return name
case ‘Латте Макиато’:
if in_stock[“coffee”] >= 1 and in_stock[“milk”] >= 2 and in_stock[“cream”] >= 1:
in_stock[“coffee”] -= 1
in_stock[“cream”] -= 1
in_stock[“milk”] -= 2
return name
case ‘Кон Панна’:
if in_stock[“coffee”] >= 1 and in_stock[“cream”] >= 1:
in_stock[“coffee”] -= 1
in_stock[“cream”] -= 1
return name
if flag:
return ‘К сожалению, не можем предложить Вам напиток’
Прямого запрета на использование функций не было. И это как раз тот случай, когда введение дополнительной функции сильно упрощает код и делает его читабельнее.
Глобальные переменные несомненное зло, но иногда отказ от них может стоить довольно дорого – в нашей ситуации пришлось бы таскать из функции в функцию рецепты, чтобы понять можем ли мы сделать такой напиток. В этом смысле использование глобальной переменной с рецептами довольно оправдано.
Обратите внимание на то, что имя переменной с рецептами написано большими буквами. Несмотря на то, что в пайтоне нет настоящих констант, существует соглашение, что имя переменной записанное большими буквами должно приравниваться по своим свойствам к константе и ее лучше не модифицировать программно.
Я согласен, просто повторюсь, условие (в задании хендбука) было понято мной так, что мы можем написать в ответ только одну функцию (ее “тело”) и ничего до, ничего после.
Введение глобальной переменной “рецептов” в вашем решении тут полностью оправдано. Я так изначально и хотел, но почему то решил ,что решение чекер не пропустит.
да и falg тоже лишний….можно просто return ‘К сожалению, не можем предложить Вам напиток’