php - 如何计算每种成分的量?
问题描述
我正在尝试解决一个问题,我需要计算像“我的三明治”这样的食谱的营养价值
我有一个包含“食谱”和“成分”的数据库以及所需的公斤量。
一个食谱可以包含成分,但也可以包含其他食谱,这些食谱又可以包含食谱/成分。
这是总重量为 0.095 公斤的“测试三明治”的“零件清单”示例。
array (
0 =>
array (
'id' => 2,
'name' => 'Test Cheese',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.015,
'depth' => 1,
),
1 =>
array (
'id' => 3,
'name' => 'Test Ham',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.03,
'depth' => 1,
),
2 =>
array (
'id' => 4,
'name' => 'Test Sesam Bread',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.05, // Only use some of the test bread (with added Sesam)
'depth' => 1,
'parts' =>
array (
0 =>
array (
'id' => 5,
'name' => 'Test Bread',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 1.0, // This a recipe for 1 kg of banana bread
'depth' => 2,
'parts' =>
array (
0 =>
array (
'id' => 6,
'name' => 'Test Flour',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.5,
'depth' => 3,
),
1 =>
array (
'id' => 7,
'name' => 'Test Water',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.3,
'depth' => 3,
),
2 =>
array (
'id' => 8,
'name' => 'Test Yeast',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.05,
'depth' => 3,
),
3 =>
array (
'id' => 9,
'name' => 'Test Banan',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.15,
'depth' => 3,
),
),
),
1 =>
array (
'id' => 10,
'name' => 'Test Sesam Seeds',
'metric_id' => 1,
'category_id' => NULL,
'quantity' => 0.1,
'depth' => 2,
),
),
),
)
如何将这种结构简化为每个“最终”成分的数量/重量列表,如面粉、水、香蕉、奶酪、火腿、芝麻等?
我编写了这个函数来运行结构,但它并没有真正完成这项工作(似乎它正确计算了总重量)
function resolveAssembly($items, $number = 1, $declaration = [])
{
$weight = 0;
foreach ($items as $item) {
// Get the quantity (weight) of the item
$amount = $item['quantity'];
// Check if the item also contains an ingredients list
if (array_key_exists('parts', $item)) {
// Get the total weight of the whole assembly
list($assembly_weight, $assembly_declaration) = resolveAssembly($item['parts'], $number * $amount, $declaration);
$declaration = array_merge($declaration, $assembly_declaration);
// Calculate the relative weight of each part in the assembly
foreach ($item['parts'] as $part) {
$weight = $weight + ($amount / $assembly_weight) * $part['quantity'];
}
} else {
// Add the amount to the declaration
if (!array_key_exists($item['name'], $declaration)) {
$declaration[$item['name']] = $number * $amount;
}
$weight = $weight + $amount;
}
}
return [$weight, $declaration];
}
编辑:合并程序集声明数组
这就是我使用上述功能的方式:
$item = Inventory::findOrFail(1); // Get "Test sandwich"
$parts = $item->getAssemblyItemsList(); // Get the parts of the "Test sandwich"
$result = resolveAssembly($parts, 1); // Get total weight of 1 "Test sandwich" + a list of amount/weight of each ingredient
resolveAssembly() 函数的当前结果:
0.095
[
"Test Cheese" => 0.015
"Test Ham" => 0.03
"Test Flour" => 0.025
"Test Water" => 0.015
"Test Yeast" => 0.0025
"Test Banan" => 0.0075
"Test Sesam Seeds" => 0.005 // Should have been factored in the bread ingredients
]
但这并不完全正确,它应该加起来为 0.095,所以我认为测试芝麻种子没有计入面包的成分(面粉、酵母、香蕉等)。
0.015+0.03+0.025+0.015+0.0025+0.0075+0.005 = 0.1公斤“测试三明治”
此外,如果这有帮助,我正在使用这个系统来存储这些食谱:https ://github.com/stevebauman/inventory/blob/v1.7/docs/ASSEMBLIES.md (但修改为存储十进制数和负数(例如处理烹饪过程中丢失或添加的水))
以下是对“测试三明治”的总重量进行总和的所有计算:
"Test Cheese: 0 + 0.015 = 0.015"
"Test Ham: 0.015 + 0.03 = 0.045"
"Test Flour: 0 + 0.5 = 0.5"
"Test Water: 0.5 + 0.3 = 0.8"
"Test Yeast: 0.8 + 0.05 = 0.85"
"Test Banan: 0.85 + 0.15 = 1"
"Test Flour: 0 + (1 / 1) * 0.5 = 0.5"
"Test Water: 0.5 + (1 / 1) * 0.3 = 0.8"
"Test Yeast: 0.8 + (1 / 1) * 0.05 = 0.85"
"Test Banan: 0.85 + (1 / 1) * 0.15 = 1"
"Test Sesam Seeds: 1 + 0.1 = 1.1"
"Test Bread: 0.045 + (0.05 / 1.1) * 1 = 0.09045454545"
"Test Sesam Seeds: 0.090454545454545 + (0.05 / 1.1) * 0.1 = 0.095"
解决方案
这应该让你更接近:
function resolveAssembly($items) {
$weight = 0;
$declaration = [];
foreach ($items as $item) {
$weight += $item['quantity'];
if (array_key_exists('parts', $item)) {
// if there are parts, get the full weight and declaration for the sub item
list($sub_total_weight, $sub_declaration) = resolveAssembly($item['parts']);
foreach ($sub_declaration as $sub_name => $sub_weight) {
if (!array_key_exists($sub_name, $declaration)) {
$declaration[$sub_name] = 0;
}
// Total weight of particular ingredient is the sub items ingredient out of the sub items full weight
// times the quantity for this particular item
$declaration[$sub_name] += $item['quantity'] * ($sub_weight / $sub_total_weight);
}
} else {
// if there are no parts, just add the quantity
if (!array_key_exists($item['name'], $declaration)) {
$declaration[$item['name']] = 0;
}
$declaration[$item['name']] += $item['quantity'];
}
}
return [$weight, $declaration];
}
这会给你这个结果:
array(2) {
[0]=>
float(0.095)
[1]=>
array(7) {
["Test Cheese"]=>
float(0.015)
["Test Ham"]=>
float(0.03)
["Test Flour"]=>
float(0.022727272727273)
["Test Water"]=>
float(0.013636363636364)
["Test Yeast"]=>
float(0.0022727272727273)
["Test Banan"]=>
float(0.0068181818181818)
["Test Sesam Seeds"]=>
float(0.0045454545454545)
}
}
如果你把上面的数字加起来,它们的总和应该是 0.095。
基本上,当你在做一个“子食谱”时,你需要知道那个食谱的总“重量”是多少,然后你可以根据那个子的数量计算出实际项目的总数。
推荐阅读
- java - Java: list1=list2 // list1==list2?
- php - 无法从 CodeIgniter 中的循环内的表单元素中获取数组数据
- django - 表单中的 django 布尔值始终返回 true
- ruby - CirclesController 中的 NoMethodError#add undefined method `circle' for nil:NilClass
- r - 如何从 data.tables 列表中计算每组的平均值?
- linux - 在 1200 Linux 服务器中安装脚本文件
- java - Spring 事务中 REQUIRES_NEW 和 NESTED 传播的行为差异
- node.js - Apache 将节点应用程序重定向到具有 .htaccess 的文件夹
- excel - 在 Excel 中编写 if 条件
- javascript - Multiple random id in element