问题
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