Php 将BOM表结构扁平化为层次结构,检测树/图中的周期
我有许多存储物料清单层次结构数据的表,如: id | childId a | b a | c c|d d|a 我需要找到闭环,比如在本例中,Php 将BOM表结构扁平化为层次结构,检测树/图中的周期,php,hierarchy,hierarchical-data,hierarchical,flat,Php,Hierarchy,Hierarchical Data,Hierarchical,Flat,我有许多存储物料清单层次结构数据的表,如: id | childId a | b a | c c|d d|a 我需要找到闭环,比如在本例中,d指向a,这会破坏系统,因为一些递归函数永远不会停止 我的想法是将此数据结构从平面转换为层次结构,然后使用递归迭代层次结构 我正在网上查阅一些知识,以及将平面结构转换为嵌套结构的大多数解决方案,包括以下情况: id | parentId 结构,其中顶级项的父ID设置为根值(例如零) 我是一名自学成才的系统开发人员多年,但现在我缺乏你们许多人在学习期间所受的教
d
指向a
,这会破坏系统,因为一些递归函数永远不会停止
我的想法是将此数据结构从平面转换为层次结构,然后使用递归迭代层次结构
我正在网上查阅一些知识,以及将平面结构转换为嵌套结构的大多数解决方案,包括以下情况:
id | parentId
结构,其中顶级项的父ID设置为根值(例如零)
我是一名自学成才的系统开发人员多年,但现在我缺乏你们许多人在学习期间所受的教育:)
编辑:图形示例
Valid trees:
a)
A
/ \
B C
\
D
/ \
E F
b)
K -> E
/ \
G B
/|\
H I J
Invalid tree (closed loop)
A
/ \
B C<----\
\ |
D /
/ \ /
E F
\
G
/|\
H I J
有效树:
(a)
A.
/ \
B C
\
D
/ \
EF
(b)
K->E
/ \
G B
/|\
HIJ
无效树(闭环)
A.
/ \
经过一点尝试和错误之后,这里是我想到的
给定关系的平面列表,它构建查找,然后在递归遍历函数中使用查找。遍历函数“记住”请求的原始零件($initialPart
),并在检测到循环时引发异常。
例如,异常:检测到循环:f=>c=>d=>f代码>
脚本:
$rows = [
['assemblyId' => 'a', 'partId' => 'b'],
['assemblyId' => 'a', 'partId' => 'c'],
['assemblyId' => 'c', 'partId' => 'd'],
['assemblyId' => 'd', 'partId' => 'e'],
['assemblyId' => 'd', 'partId' => 'f'],
['assemblyId' => 'f', 'partId' => 'c'],
['assemblyId' => 'f', 'partId' => 'g'],
['assemblyId' => 'g', 'partId' => 'h'],
['assemblyId' => 'g', 'partId' => 'i'],
['assemblyId' => 'g', 'partId' => 'j'],
];
$assemblyLookup = [];
foreach ($rows as $row) {
$assemblyLookup[$row['assemblyId']][$row['partId']] = $row;
}
function getTree(&$part, $initialPart = null, $path = '', $level = 0, $maxLevel = 100) {
global $assemblyLookup;
if ($initialPart === null) {
$initialPart = $part;
}
if ($level >= $maxLevel) {
return;
}
$path .= '=>' . $part['partId'];
if (is_array($assemblyLookup[$part['partId']])) {
$lookup = $assemblyLookup[$part['partId']];
foreach ($lookup as $child) {
if ($child['partId'] === $initialPart['partId']) {
$circularPath = substr($path, 2) . '=>' . $child['partId'] . '!';
throw new Exception("Loop detected: " . $circularPath);
return;
}
$part['children'][$child['partId']] = $child;
getTree($part['children'][$child['partId']], $initialPart, $path, ++$level, $maxLevel);
}
} else {
$path .= ';';
$part['path'] = substr($path, 2); // Strip arrow from left side
}
return $part;
}
$part = ['partId' => 'f'];
$tree = getTree($part);
的确很有趣,但在我的例子中,它不是一个链表,而是一棵树。