如何在 python 中按食材和单位合并多个食谱的用量?
可以用字典累加用量,以 (食材名称, 单位) 元组作为键。名称和单位都相同的条目会合并;同一种食材如果使用不同单位,则分别保留。
例如,("番茄", "克") 的用量可以累加,("黄瓜", "根") 和 ("黄瓜", "克") 则会保存在不同的键下。
先把食材整理成结构化数据
从网页抓取数据后,先把每条记录拆成食材名称、单位和数值用量三个字段,避免在求和时再处理 "500 克番茄" 这样的整段文本。
每条记录用一个元组表示,字段顺序固定为 (名称, 单位, 用量):
recipe_1 = [
("番茄", "克", 500),
("橄榄油", "dl", 1),
("黄瓜", "根", 2),
]
recipe_2 = [
("牛油果", "个", 2),
("番茄", "克", 200),
("橄榄油", "dl", 1),
("黄瓜", "克", 100),
]
按名称和单位累加
遍历所有食谱,用每条记录的 (name, unit) 作为键。键已存在时,加上本次用量;首次遇到时,从 0 开始累加。
def merge_recipes(recipes):
totals = {}
for recipe in recipes:
for name, unit, amount in recipe:
key = (name, unit)
totals[key] = totals.get(key, 0) + amount
return totals
shopping_list = merge_recipes([recipe_1, recipe_2])
for (name, unit), amount in shopping_list.items():
print(f"{amount} {unit} {name}")
把这段代码接在前面的数据后运行,输出为:
700 克 番茄
2 dl 橄榄油
2 根 黄瓜
2 个 牛油果
100 克 黄瓜
读取当前累计用量的是:
totals.get(key, 0)
如果字典中还没有这个键,它会返回默认值 0。
Python 3.7 及以上版本的字典保证保留插入顺序,因此结果会按每个食材与单位组合首次出现的顺序输出,后续累加不会改变其位置。
处理抓取数据时的注意事项
统一名称和单位的写法
字典按键的实际值分组,不会自动识别同义词。例如,"番茄" 和 "西红柿" 会被当作两种食材,"克" 和 "g" 也会被当作两种单位。
如果数据源混用了这些写法,可以先用映射表统一:
name_aliases = {
"西红柿": "番茄",
}
unit_aliases = {
"g": "克",
"grams": "克",
}
在生成 key 之前,先处理名称和单位:
name = name.strip()
unit = unit.strip()
name = name_aliases.get(name, name)
unit = unit_aliases.get(unit, unit)
key = (name, unit)
映射规则要根据抓取的数据确定,避免误合并实际不同的食材。
将用量转换为数值
示例中的 amount 已经是整数。如果抓到的是 "500" 这样的字符串,应在整理数据时将它转换成数值。
"1/2"、"半根" 或 "适量" 需要单独制定解析规则。其中,“适量”没有可直接相加的数值,可以保留为备注。
需要精确累加十进制小数时,可以使用 Decimal,并从字符串构造,例如 Decimal("0.1"),避免先转换为 float 带来的误差。
单位换算需要另外处理
上面的函数只合并单位完全相同的条目。"千克" 和 "克" 虽然都表示重量,仍会分别保留。要合并它们,需要先将用量换算到统一单位,并更新单位字段。
仅凭“根”和“克”无法确定换算关系,因此将黄瓜保留为两条记录符合题目要求。
备注:内容仅供参考。
