Flattern a tree and keeping track of the path to each leaf

只愿长相守 提交于 2019-12-11 16:43:25

问题


I have a "food recipe" where all sub ingredients that are used to make the recipe is structured in a tree

I've earlier gotten some help to create some code to flattern the tree and calculating the weight of each base ingredient (leaf): How to calculate the amount of each ingredient?

But now I also want to track how each ingredient is prepared (but still summing up ingredients weight).

I have therefor added an extra attribute to each node called "preparation"

but I struggle to find out how I can keep track of the full preparation chain.

Here is an example of a recipe tree structure:

$tree = [
    [
        'name' => 'a',
        'weight' => 1,
        'preparation' => 'boiled',
        'tree' => [
            [
                'name' => 'c',
                'weight' => 3,
                'preparation' => 'baked',
            ],
            [
                'name' => 'c',
                'weight' => 3,
                'preparation' => 'fried',
            ],
        ]
    ],
    [
        'name' => 'b',
        'weight' => 1,
        'preparation' => 'boiled',
        'tree' => [
            [
                'name' => 'd',
                'weight' => 4,
                'preparation' => 'none',
                'tree' => [
                    [
                        'name' => 'e',
                        'weight' => 1,
                        'preparation' => 'fried',
                    ],
                    [
                        'name' => 'f',
                        'weight' => 1,
                        'preparation' => 'none',
                    ]
                ]
            ],
            [
                'name' => 'c',
                'weight' => 1,
                'preparation' => 'baked',              // b[1]c has the same "preperation chain" as a[0]c
            ]
        ]
    ],
    [
        'name' => 'c',
        'weight' => 1,
        'preparation' => 'none',
    ]
];

And I want it to be reduced to an array of each "base ingredient weight" (leaf) and preparation chain (path).

array (
  'c-baked,boiled'      => 0.7,
  'c-fried,boiled'      => 0.5,
  'e-fried,none,boiled' => 0.4,
  'f-none,none,boiled'  => 0.4,
  'c-none'              => 1,
)

For the sake of the argument, this how the result looks like, without preparation taken into account:

array (
  'c' => 2.2,   // 0.7 + 0.5 + 1
  'e' => 0.4,
  'f' => 0.4,
)

I have only been able to get the code to track the preparation of the base ingredient (leaf), not the full chain:

array (
  'c-baked,boiled' => 0.2,
  'c-fried,boiled' => 0.5,
  'e-fried,none,boiled' => 0.4,
  'f-none,none,boiled' => 0.4,
  'c-none' => 1,
)

Here is the how the code looks:

//function getBaseIngredients(array $tree): array
function getBaseIngredients(array $tree, $preparation = null): array
{
    $leafs = [];

    // Loop through the nodes in the tree if the node 
    // is a leaf we sum the weight, otherwise we recursivly
    // call our self and resolve the branch
    foreach($tree as $node){
        if(empty($node['tree']))
        {

            // if there are no parts, just add the weight

            //$key = $node['name'] . '-' . $node['preparation'];
            $key = $node['name'] . '-' . $node['preparation'] . $preparation;

            if(!array_key_exists($node['name'], $leafs)) {
                $leafs[$key] = 0;
            }

            $leafs[$key] += $node['weight'];

        } else {

            // if there sub nodes, get the full weight node
            $nodes = getBaseIngredients($node['tree'], $preparation);
            $total = array_sum($nodes);

            // Scale each sub node according to the parent
            foreach($nodes as $key => $weight){

                if(!array_key_exists($key, $leafs)) {
                    //$leafs[$key] = 0;
                    $leafs[$key . ',' . $node['preparation']] = 0;
                }

                // Total weight of particular node is the 
                // sub node out of the sub node full weight
                // times the weight for this particular leaf

                // $leafs[$key] += $node['weight'] * ($weight / $total);
                $leafs[$key . ',' . $node['preparation']] += $node['weight'] * ($weight / $total);
            }
        }
    }

    return $leafs;
}

来源:https://stackoverflow.com/questions/56909578/flattern-a-tree-and-keeping-track-of-the-path-to-each-leaf

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!