碰到循环树结构问题
需求是传入一个id,例如:B3OCM,通过循环得到只包含B3OCM的树结构:同时单板级和之前节点的不变
请注意! 此段树结构要寻找的 boardId 是数组内包多个id
const BoardMenus = [
{
key: '/neConfig/dvm/Spec/SystemConfiguration',
display: ['System Configuration', '配置管理'],
children: [
{
key: '/Subrack',
display: ['Subrack', '单板级'],
children: [
{
key: '/Configuration',
display: ['Configuration', '配置'],
children: [
{
key: '/WDM_Interface/WDMInterface', display: ['WDM Interface', 'WDM接口'],
boardId: ['B3OCM', 'B3PDU'],
type: '1'
},
{
key: '/Optical_Power_Management/OpticalPowerManagement', display: ['Optical Power Management', '光功率管理'],
boardId: ['B3PDU', 'B3OCM'],
type: '1'
},
{
key: '/Environment_Monitor', display: ['Environment Monitor', '环境监视配置'],
children: [
{
key: '/Environment_Monitor_Interface/Monitor_Interface', display: ['Environment Monitor Interface', '环境监视接口'],
boardId: ['B3PDU', 'B3OCM'],
type: '1'
}
]
},
{
key: '/Flexgrid_Monitor_Wavelength/FlexgridMonitorWavelength', display: ['Flexgrid Monitor Wavelength', 'Flexgrid监控器波长'],
boardId: ['B3LDU'],
type: '1'
},
{
key: '/Threshold_Management/ThresholdManagement', display: ['Threshold Management', '阈值管理'],
boardId: ['B3LDU'],
type: '1'
},
]
},
{
key: '/Alarm',
display: ['Board Alarm', '告警'],
children: [
{
key: '/Alarm_Severity_Auto/AlarmSeverityAuto', display: ['Alarm Severity Auto', '告警级别和自动上报设置'],
boardId: ['B3OCM', 'B3PDU'],
type: '2'
},
{ key: '/Alarm_Suppression/AlarmSuppression', display: ['Alarm Suppression', '告警抑制'] },
{ key: '/Alarm_Reversion/AlarmReversion', display: ['Alarm Reversion', '告警恢复'] },
]
},
{
key: '/Performance',
display: ['Subrack Performance', '性能'],
children: [
{
key: '/CurrentPerformance', display: ['Current Performance', '当前性能'],
boardId: ['B3OCM', 'B3LDU', 'B3PDU'],
type: '3'
},
],
},
],
},
]
}
]
如果传入上面树结构 并且传入id B3OCM
想要得到的结构是这样的
const Menus = [
{
key: '/neConfig/dvm/Spec/SystemConfiguration',
display: ['System Configuration', '配置管理'],
children: [
{
key: '/Subrack',
display: ['Subrack', '单板级'],
children: [
{
key: '/Configuration',
display: ['Configuration', '配置'],
type: '1',
children: [
{
key: '/WDM_Interface/WDMInterface', display: ['WDM Interface', 'WDM接口'],
boardId: ['B3OCM', 'B3PDU'],
type: '1'
},
{
key: '/Optical_Power_Management/OpticalPowerManagement', display: ['Optical Power Management', '光功率管理'],
boardId: ['B3PDU', 'B3OCM'],
type: '1'
},
{
key: '/Environment_Monitor', display: ['Environment Monitor', '环境监视配置'],
children: [
{
key: '/Environment_Monitor_Interface/Monitor_Interface', display: ['Environment Monitor Interface', '环境监视接口'],
boardId: ['B3PDU', 'B3OCM'],
type: '1'
}
]
},
]
},
{
key: '/Alarm',
display: ['Board Alarm', '告警'],
type: '2',
children: [
{
key: '/Alarm_Severity_Auto/AlarmSeverityAuto', display: ['Alarm Severity Auto', '告警级别和自动上报设置'],
boardId: ['B3OCM', 'B3PDU'],
type: '2'
},
]
},
{
key: '/Performance',
display: ['Subrack Performance', '性能'],
type: '3',
children: [
{
key: '/CurrentPerformance', display: ['Current Performance', '当前性能'],
boardId: ['B3OCM', 'B3LDU', 'B3PDU'],
type: '3'
},
],
},
],
},
]
}
]
这个问题看起来需要对 BoardMenus 数组进行递归遍历,找到包含特定 boardId 的节点,并且保留其祖先节点的信息。以下是一个可能的实现方式:
function filterBoardMenusById(menus, targetId) {
return menus.filter(menu => {
if (menu.children) {
menu.children = filterBoardMenusById(menu.children, targetId);
}
if (menu.boardId && menu.boardId.includes(targetId)) {
delete menu.boardId; // 删除目标节点的 boardId 属性
return true;
}
return menu.children && menu.children.length > 0;
});
}
// 例如,查找包含 B3OCM 的树结构
const targetId = 'B3OCM';
const Menus = filterBoardMenusById([...BoardMenus], targetId);
这里的 filterBoardMenusById 函数接收一个数组参数 menus 和一个字符串参数 targetId,返回一个新的数组。它会先对 menus 进行过滤,对于每个元素:
如果有 children 属性,递归调用 filterBoardMenusById 并更新 children 属性。
如果有 boardId 属性,检查其是否包含 targetId,如果是则删除该属性并返回 true。
如果都不符合,则检查是否有子节点,并且子节点个数大于 0,如果是则返回 true。
最终返回的新数组就是符合条件的树结构。
用递归方法遍历你需要的数组
function getOb(arr,key){
arr.map(item=>{
if(item.key == key){
console.log(item);
return item
}else{
item.children && getOb(item.children,key)
}
})
}
```bash
```
该回答引用ChatGPT
你可以使用递归函数来遍历该树结构,并找到只包含指定id的子树。以下是一个可以实现这个功能的JavaScript函数示例:
function findSubtreeById(tree, id) {
if (tree.key && tree.key.includes(id)) {
// 当前节点包含指定id,直接返回当前节点
return tree;
} else if (tree.children && tree.children.length > 0) {
// 当前节点有子节点,递归遍历子节点
for (let i = 0; i < tree.children.length; i++) {
const subtree = findSubtreeById(tree.children[i], id);
if (subtree) {
// 子树中包含指定id,返回子树
return subtree;
}
}
}
// 当前节点及其子节点均不包含指定id,返回null
return null;
}
你可以将该函数应用到你的数据结构上,如下所示:
const id = "B3OCM";
const subTree = findSubtreeById(BoardMenus[0], id);
console.log(subTree);
这里假设你的数据结构始终是一个数组,因此在调用findSubtreeById函数时,使用BoardMenus[0]作为树的根节点。函数返回包含指定id的子树(如果存在),并打印结果到控制台。
请注意,此示例假定每个节点都有一个唯一的key属性。如果你的数据结构中没有key属性,你需要选择一个其他属性来代替它,并在findSubtreeById函数中使用它。
可以采用递归或栈来完成:
function findMenuByBoardId(menus, boardIds) {
const filteredMenus = [];
function traverse(node) {
if (node.children) {
node.children = node.children.filter(child => {
const shouldKeep = traverse(child);
if (!shouldKeep) return false;
return true;
});
}
if (node.boardId) {
if (boardIds.includes(node.boardId[0])) {
if (node.type) {
delete node.boardId;
filteredMenus.push(node);
return true;
} else {
filteredMenus.push(node);
return true;
}
} else {
return false;
}
}
if (node.children && node.children.length > 0) {
return true;
} else {
return false;
}
}
menus.forEach(menu => {
const shouldKeep = traverse(menu);
if (shouldKeep) {
filteredMenus.push(menu);
}
});
return filteredMenus;
}
以下答案基于ChatGPT与GISer Liu编写:
这个问题可以使用递归解决。
- 遍历每个节点,如果它的 boardId 中包含了传入的 id,那么就将该节点加入到结果数组中;
- 对于每个包含该节点的节点,递归调用该节点,将返回结果加入到该节点的 children 数组中;
- 如果该节点不包含传入的 id,那么就对该节点的 children 数组递归调用步骤 2。
参考GPT和自己的思路,以下是代码实现,可以传入要查询的ID和树结构,会返回符合要求的新树结构:
function findBoardMenusById(id, menus) {
if (!Array.isArray(menus) || menus.length === 0) return null;
for (let i = 0; i < menus.length; i++) {
const menu = menus[i];
if (menu.boardId?.includes(id)) {
return {
...menu,
children: menu.children ? [] : undefined
};
}
if (menu.children) {
const found = findBoardMenusById(id, menu.children);
if (found) {
const newMenu = {
...menu,
children: [found]
};
return {
...newMenu,
children: menu.children
.filter((child) => child !== found)
.map((child) =>
child.children ? { ...child, children: [] } : child
)
};
}
}
}
return null;
}
function filterBoardMenusById(id, menus) {
if (!Array.isArray(menus) || menus.length === 0) return null;
const filteredMenus = menus.reduce((acc, menu) => {
const found = findBoardMenusById(id, [menu]);
if (found) {
acc.push(found);
}
return acc;
}, []);
return filteredMenus;
}
使用方法:
const id = 'B3OCM';
const filteredMenus = filterBoardMenusById(id, BoardMenus);
console.log(filteredMenus);
如果对您有帮助,请给与采纳,谢谢。
用递归方法遍历你需要的数组
function getOb(arr,key){
arr.map(item=>{
if(item.key == key){
console.log(item);
return item
}else{
item.children && getOb(item.children,key)
}
})
}
1.定义递归函数 findBoard,函数参数包括当前节点 ID 和目标节点 ID 数组。
2.在 findBoard 中,首先判断当前节点 ID 是否为目标节点 ID 数组中的一个,如果是,则将该节点加入结果列表中。
3.然后遍历当前节点的子节点,递归调用 findBoard 函数查找子节点,将返回的结果加入结果列表中。
4.最后返回结果列表。
5.对于每个传入的 ID,都调用一次 findBoard 函数,最后将所有结果合并去重。
function findBoard(nodeId, targetIds) {
let result = [];
if (targetIds.includes(nodeId)) {
// 当前节点是目标节点之一,加入结果列表
result.push(nodeId);
}
// 遍历子节点,递归查找
for (let childNode of nodeId.children) {
let childResult = findBoard(childNode.id, targetIds);
// 将子节点的结果加入结果列表
result = result.concat(childResult);
}
return result;
}
function findBoards(targetIds) {
let result = [];
for (let targetId of targetIds) {
let boardResult = findBoard(rootNodeId, [targetId]);
result = result.concat(boardResult);
}
// 合并结果并去重
result = [...new Set(result)];
return result;
}
其中 nodeId 是当前节点 ID,targetIds 是目标节点 ID 数组,rootNodeId 是树的根节点 ID,children 是当前节点的子节点数组。函数 findBoards 用来查找多个目标节点,将结果合并去重返回。
这种多层的使用递归即可(递归就是自己调用自己),在递归函数里面写你想要的格式