我正在尝试生成一个安装在机架中的设备的动态列表。假设我有以下mysql数据:
ID Name Order Owner Units
--------------------------------------
56 9U Rackmount 0 0 9.0
54 Rackmount 8 56 1.2
9 RPi 4 B 2 59 0.1
7 MacMini B 2 54 0.1
32 Router 1 56 1.0
14 RPi 4 C2 4 59 0.1
33 Switch A 2 56 1.0
35 POE Switch 3 56 1.0
8 RPi 4 A 1 59 0.1
13 RPi 4 C1 3 59 0.1
59 Rackmount 4 56 1.4
28 Powerstrip 5 56 1.0
38 Switch B 6 56 1.0
我想通过关联数组生成列表(如下((可能使用$order作为键(?"单位"列可以帮助描述设备将占用的单位数量;整数是垂直的,而十进制值是水平单位:
9U Rackmount [56]
--------------------------
1: Router [32]
2: Switch A [33]
3: POE Switch [35]
4: Rackmount [59]
1: RPi 4 A [8]
2: RPi 4 B [9]
3: RPi 4 C1 [13]
4: RPi 4 C2 [14]
5: Powerstrip [28]
6: Switch B [38]
7: (empty)
8: Rackmount [54]
1: (empty)
2: MacMini B [7]
9: (empty)
这就是我提出的(递归函数(,但它甚至没有生成正确的顺序。。
function tree_build ($item) {
$found = array(); $branch = array();
$branch = get_children_via_owner($item);
$order = get_placement_within_owner($item);
if (count($branch) > 0) {
foreach ($branch as $twig) { $found[] = tree_build($twig); }
} else {
return(array($order => $item))
}
return(array(array($order => $item), $found));
}
有什么想法吗?
是的,递归函数的方向是正确的,但您没有显示get_children_via_owner
、get_placement_within_owner
和tree_build
在做什么,而且没有排序,似乎也没有考虑空元素。
递归函数应该做3件事:
- 搜索初始数组以查找所有具有您正在评估的父数组的数组
- 根据
Order
对数组进行排序 - 将缺少的值添加为空槽
以下是代码中的样子:
function buildTree(int $Owner = 0) {
global $racks;
$ret = [];
foreach ($racks as $id => $rack) {
if ($rack['Owner'] != $Owner) { // Exclude elements with different parent
continue;
}
$rack['slots'] = buildTree($id); // Recursive
ksort($rack['slots']); // Sort based on Order
if (sizeof($rack['slots'])) {
$max_order = array_key_last($rack['slots']);
for ($i = 1; $i <= $max_order; $i++) { // Fill empty slots
if (!isset($rack['slots'][$i])) {
$rack['slots'][] = ['Name' => '(empty)', 'ID' => 0, 'Order' => $i, 'Units' => 0];
}
}
usort($rack['slots'], function ($a, $b) {
return $b['Order'] < $a['Order'];
});
}
$ret[$rack['Order']] = $rack; // User Order as array key for easy sorting
}
return $ret;
}
然后,对于打印,您也可以编写一个递归函数,但考虑到您对每个级别使用非常不同的样式,如果您确定只有3个级别,则可能更容易执行嵌套foreach,如下所示。
foreach ($tree as $rack) {
echo $rack['Name'].' ['.$rack['ID'].']'.PHP_EOL;
echo "---------".PHP_EOL;
if (!empty($rack['slots']) && sizeof($rack['slots'])) {
foreach ($rack['slots'] as $sub1) {
echo $sub1['Order'].": ".$sub1['Name'].' ['.$sub1['ID'].']'.PHP_EOL;
if (!empty($sub1['slots']) && sizeof($sub1['slots'])) {
foreach ($sub1['slots'] as $sub2) {
echo " ".$sub2['Order'].": ".$sub2['Name'].' ['.$sub2['ID'].']'.PHP_EOL;
}
}
}
}
}
除了最后一个空插槽之外,最终的输出正是您想要的,我认为您没有足够的数据来确定机架末端是否有空插槽。
9U Rackmount [56]
---------
1: Router [32]
2: Switch A [33]
3: POE Switch [35]
4: Rackmount [59]
1: RPi 4 A [8]
2: RPi 4 B [9]
3: RPi 4 C1 [13]
4: RPi 4 C2 [14]
5: Powerstrip [28]
6: Switch B [38]
7: (empty) [0]
8: Rackmount [54]
1: (empty) [0]
2: MacMini B [7]
作为参考,这是您生成初始阵列的方式
$tree = buildTree();
这是的初始查询
$query = 'SELECT * FROM racks ORDER BY `Owner`';
$racks = [];
if ($stmt = $sql_connection->prepare($query)) {
$stmt->execute();
$result = $stmt->get_result();
while ($data = $result->fetch_assoc()) {
$racks[$data['ID']] = $data;
}
}