如何在递归函数中将父级面包屑传递给子级,用于构建 PHP 分类树数组?

huangapple go评论50阅读模式
英文:

How can I carry over parent breadcrumbs to children in a recursive function for building a PHP array tree of categories?

问题

我有一个查询,用来拉取所有的食品类别,还有一个递归创建树的函数,最后是另一个递归函数,它在添加深度指示器的同时将其展平。

递归工作正常。我在将父级面包屑传递给每个子级时遇到了困难。每个级别都必须有一个面包屑,即使是最后一个。

虽然面包屑的积累要求当前节点是特定父级的,但该函数以某种方式将所有过去的面包屑都传递过去,甚至来自其他父级的子级的面包屑也会被传递。结构的其余部分遵守父/子关系。我不知道为什么面包屑没有按预期工作。

这是查询结果的一个小样本。

这是我处理数据库查询结果的尝试(树在此完成后展平)。

这个部分的数据库是这样的,但其他部分更深层。

  • 饮料
    • 酒精
    • 碳酸饮料

完整的结构需要大量空间来显示,所以这只是一个包含“碳酸饮料”的节点。它正确地继承了“饮料”,但然后它还包含来自“酒精”的面包屑,这不是“碳酸饮料”链的一部分。我不知道“酒精”的面包屑是如何进入“碳酸饮料”函数实例链的。树的其余部分构建正确。这不是一个局部问题——“饮料”也进入了“肉类”顶层节点。

当前行为(请注意“酒精”存在):

预期行为:

我理解这个结构可能比实际需要的更冗长和更深,如果它是关联的而不是索引的话可能会更好,但出于与问题无关且不明显的原因,它就是现在的样子。

我对带有其parent_id的展平数组进行了另一个失败的尝试,并添加了深度指示器,但在那里找到的解决方案也可以。如何调整这个,使得只有给定链的面包屑积累?

英文:

I have a query that pulls all food categories, a function that iterates recursively to create a tree, and finally another recursive function that flattens it while adding a depth indicator.

The recursion works fine. I am having difficulty passing the parent breadcrumbs down to each children. There must be a crumb for each level, even the last.

Although crumb accumulation requires the current node be for a specific parent, the function carries over all past crumbs somehow, even crumbs from children of other parents. The rest of the structure abides by the parent/children relationship. I cannot see why the breadcrumbs don't.

a small sample of the query results

$QueryResults = array
(
0 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 42
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Alcoholic'
)
)
),
1 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 39
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Beef'
)
)
),
2 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 1
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => NULL
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Beverages'
)
)
),
3 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 44
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Carbonated'
)
)
),
4 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 46
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 1
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Coffee'
)
)
),
5 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 4
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => NULL
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Meats'
)
)
),
6 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 44
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Processed Meats'
)
)
),
7 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 45
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 44
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Luncheon Meats'
)
)
),
8 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 7
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Pork'
)
)
),
9 => array
(
'Fields' => array
(
0 => array
(
'FieldName' => 'id',
'Value' => 8
),
1 => array
(
'FieldName' => 'parent_id',
'Value' => 4
),
2 => array
(
'FieldName' => 'name',
'Value' => 'Poultry'
)
)
)
)
;

here's my attempt at processing the database query results (the tree flattens after this completes).

function buildTree($elements, $parentId, $crumbs) {
$branch = array();
foreach ($elements as $element) {
if ($element['Fields'][1]['Value'] == $parentId) {
$currentCrumbs[] = array('Fields' => array(0 => array('FieldName' => 'id','Value' => $element['Fields'][0]['Value']),1 => array('FieldName' => 'Crumb','Value' => $element['Fields'][2]['Value'])));
if (is_array($crumbs)) { // lower levels
$combinedCrumbs = array_merge($crumbs, $currentCrumbs);
} else { // top level
$combinedCrumbs = $currentCrumbs;
}
$element['BreadCrumbs'] = $combinedCrumbs;
$children = buildTree($elements, $element['Fields'][0]['Value'], $combinedCrumbs);
if ($children) {
$element['SubGroups'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}

This part of the database is like this, but other parts are more layers deep:

  • Beverages
    • Alcoholic
    • Carbonated

The full structure takes a lot of space to display, so this is just one node containing "carbonated" beverages. It correctly carries over the "Beverages", but then it also contains the crumb from "Alcoholic" leaf which is not a part of the "Carbonated" chain. I don't know how the crumb from the "Alcoholic" instance of this function made its way into the "Carbonated" chain of function instances. The rest of the tree builds correctly. It's not a local problem--"Beverages" also makes its way into the "Meats" top level node.

Current behavior (notice how "Alcoholic" is present):

[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => parent_id
[Value] => 1
)
[2] => Array
(
[FieldName] => name
[Value] => Carbonated
)
)
[BreadCrumbs] => Array
(
[0] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 1
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Beverages
)
)
)
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 42
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Alcoholic
)
)
)
[2] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Carbonated
)
)
)
)
)

Expected Behavior:

[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => parent_id
[Value] => 1
)
[2] => Array
(
[FieldName] => name
[Value] => Carbonated
)
)
[BreadCrumbs] => Array
(
[0] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 1
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Beverages
)
)
)
[1] => Array
(
[Fields] => Array
(
[0] => Array
(
[FieldName] => id
[Value] => 44
)
[1] => Array
(
[FieldName] => Crumb
[Value] => Carbonated
)
)
)
)
)

I Understand this structure is more verbose and deeper than it probably needs to be if it were associative instead of indexed, but for reasons not related and in ways not obvious, it is what it is.

I have a separate failed effort on the flattened array with its parent_id intact and a depth indicator added, but a solution there would work too.

How can i adjust this such that only the crumbs for the given chain accumulate?

答案1

得分: 0

以下是您要求的代码部分的中文翻译:

function buildTree($elements, $parentId, $crumbs) {
  $branch = array();
    
  foreach ($elements as $element) {
    if ($element['Fields'][1]['Value'] == $parentId) {

      $currentCrumbs = array(array('Fields' => array(0 => array('FieldName' => 'id', 'Value' => $element['Fields'][0]['Value']), 1 => array('FieldName' => 'Crumb', 'Value' => $element['Fields'][2]['Value']))));


      if (is_array($crumbs)) { // 更低层级
        $combinedCrumbs = combineArrays($crumbs, $currentCrumbs);
      } else { // 顶层
        $combinedCrumbs = $currentCrumbs;
      }
      $element['BreadCrumbs'] = $combinedCrumbs;

      $children = buildTree($elements, $element['Fields'][0]['Value'], $combinedCrumbs);
      if ($children) {
        $element['SubGroups'] = $children;
      }
      $branch[] = $element;

    }
  }

  return $branch;
}

请注意,我只翻译了代码部分,没有包含其他内容。

英文:

Looked into it and this worked for me:

function buildTree($elements, $parentId, $crumbs) {
$branch = array();
foreach ($elements as $element) {
if ($element['Fields'][1]['Value'] == $parentId) {
$currentCrumbs = array(array('Fields' => array(0 => array('FieldName' => 'id','Value' => $element['Fields'][0]['Value']),1 => array('FieldName' => 'Crumb','Value' => $element['Fields'][2]['Value']))));
if (is_array($crumbs)) { // lower levels
$combinedCrumbs = combineArrays($crumbs, $currentCrumbs);
} else { // top level
$combinedCrumbs = $currentCrumbs;
}
$element['BreadCrumbs'] = $combinedCrumbs;
$children = buildTree($elements, $element['Fields'][0]['Value'], $combinedCrumbs);
if ($children) {
$element['SubGroups'] = $children;
}
$branch[] = $element;
}
}
return $branch;
}

The main problem was that you have appended elements to $currentCrumbs, like

$currentCrumbs[]= ...

So, when there are more elements to process, that is, there are more than one siblings, such as in the case of Alcoholic and Carbonated, whose parent is Beverages, at the first step Alcoholic is "added" to a non-existing array, that is, a new array is being created with a single element, Alcoholic. Then, when it is proceeding to the second step, that is, to Carbonated, then Alcoholic is already in $currentCrumbs and Carbonated is added to it, resulting in an array of two elements.

Instead, I'm creating a new array at every iteration of the loop.

Also, I wrapped an array around the array and separated the merging. The result was a success:

如何在递归函数中将父级面包屑传递给子级,用于构建 PHP 分类树数组?

huangapple
  • 本文由 发表于 2023年5月30日 07:51:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76360871.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定