首页 > 解决方案 > 如何计算每种成分的量?

问题描述

我正在尝试解决一个问题,我需要计算像“我的三明治”这样的食谱的营养价值

我有一个包含“食谱”和“成分”的数据库以及所需的公斤量。

一个食谱可以包含成分,但也可以包含其他食谱,这些食谱又可以包含食谱/成分。

这是总重量为 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"

标签: phpnested-sets

解决方案


这应该让你更接近:

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。

基本上,当你在做一个“子食谱”时,你需要知道那个食谱的总“重量”是多少,然后你可以根据那个子的数量计算出实际项目的总数。


推荐阅读