根据id递归获取树段
Recursively get segment of tree according to id
我正在尝试根据 id 获取树段。 id 可能位于根目录中,也可能位于 children 中的任何位置。我的目标是获取整个家谱线,而不是其他 non-related 数据。
我有整个数据树,还有一个 id。
想法是递归地执行此操作,因为 children 的数量未知。
import "./styles.css";
export default function App() {
const folderTree = [
{
id: "1-1",
children: [
{
id: "1-2",
parentId: "1-1",
children: []
}
]
},
{
id: "2-1",
children: [
{
id: "2-2",
parentId: "2-1",
children: [
{
id: "2-4",
parentId: "2-2",
children: []
}
]
},
{
id: "2-3",
parentId: "2-1",
children: []
}
]
}
];
const getRelatedTreeFolders = (folders, selectedFolderId) => {
//** goes top to bottom
const recursiveChildCheck = (folder, id) => {
// THIS trial failed
// let foundNested = false;
// if (folder.id === id) {
// return true;
// }
// function recurse(folder) {
// if (!folder.hasOwnProperty("children") || folder.children.length === 0)
// return;
// for (var i = 0; i < folder.children.length; i++) {
// if (folder.children[i].id === id) {
// foundNested = true;
// break;
// } else {
// if (folder.children[i].children.length > 0) {
// recurse(folder.children[i].children);
// if (foundNested) {
// break;
// }
// }
// }
// }
// }
// recurse(folder);
// return foundNested;
const aChildHasIt =
folder.children.length > 0 && folder.children.some((f) => f.id === id);
if (aChildHasIt) return true;
let nestedChildHasIt = false;
/** The problem seems to be here */
folder.children.forEach((childFolder) => {
// Is using a forEach loop the correct way?
// ideally it seems there is a simple way to do a recursive .some on the dhildren...
childFolder.children.length>0 && recursiveChildCheck(childFolder, id)
});
if (nestedChildHasIt) return true;
folder.children && folder.children.forEach(recursiveChildCheck);
};
const treeSegment = folders.reduce((result = [], folder) => {
if (
folder.id === selectedFolderId ||
recursiveChildCheck(folder, selectedFolderId)
) {
result.push(folder);
}
return result;
}, []);
return treeSegment;
};
const selectedFolderId = "2-1";
const selectedFolderId1 = "2-2";
const selectedFolderId2 = "2-4";
const selectedFolderId3 = "2-3";
const selectedFolderId4 = "3-1";
const selectedFolderId5 = "1-1";
const selectedFolderId6 = "1-2";
console.log("parent");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId));
console.log("child");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId1));
console.log("grandchild"); // this fails
console.log(getRelatedTreeFolders(folderTree, selectedFolderId2));
console.log("sibling");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId3));
console.log("not found");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId4));
console.log("other parent");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId5));
console.log("other child");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId6));
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{/* <h2>{JSON.stringify(result)}</h2> */}
</div>
);
}
一些问题:
recursiveChildCheck
应该是 return 一个布尔值,但在某些情况下,没有任何内容 (undefined
) 是 returned,因为 return
语句在以下表达式中丢失:
folder.children && folder.children.forEach(recursiveChildCheck);
此外,在上面的表达式中,&&
运算符的第二个操作数将永远不会被计算,因为 folder.children
是一个数组,数组总是真实的,即使空数组。为了给第二个操作数一个机会,第一个操作数应该是 folder.children.length > 0
但即使进行了该更正,第二个操作数 始终 的计算结果为 undefined
,因为这就是 .forEach
returns 是设计使然。你应该在那里有一个方法调用 returns 一个布尔值,比如 some
.
nestedChildHasIt
在初始化后永远不会得到任何其他值,因此下面的 return true
永远不会发生:
if (nestedChildHasIt) return true;
您可能打算在前面的 forEach
循环中将 nestedChildHasIt
设置为 true,但似乎您在这里有另一种方法来执行与其他 forEach
相同的操作你最后的循环。
我认为你一直在努力解决的问题是你需要同时检查一个布尔条件(子树是否有 id
?) 和 你需要将子项过滤为符合此条件的子项,创建一个具有此唯一子项的新节点。
更正后的代码:
function getForestSegment(nodes, id) {
function recur(nodes) {
for (const node of nodes) {
if (node.id === id) return [node];
const children = recur(node.children);
if (children.length) return [{ ...node, children}];
}
return [];
}
return recur(nodes);
}
// Example from question:
const forest = [{id: "1-1",children: [{id: "1-2",parentId: "1-1",children: []}]},{id: "2-1",children: [{id: "2-2",parentId: "2-1",children: [{id: "2-4",parentId: "2-2",children: []}]},{id: "2-3",parentId: "2-1",children: []}]}];
for (const id of ["2-1", "2-2", "2-4", "2-3", "3-1", "1-1", "1-2"]) {
console.log(id);
console.log(getForestSegment(forest, id));
}
我正在尝试根据 id 获取树段。 id 可能位于根目录中,也可能位于 children 中的任何位置。我的目标是获取整个家谱线,而不是其他 non-related 数据。
我有整个数据树,还有一个 id。
想法是递归地执行此操作,因为 children 的数量未知。
import "./styles.css";
export default function App() {
const folderTree = [
{
id: "1-1",
children: [
{
id: "1-2",
parentId: "1-1",
children: []
}
]
},
{
id: "2-1",
children: [
{
id: "2-2",
parentId: "2-1",
children: [
{
id: "2-4",
parentId: "2-2",
children: []
}
]
},
{
id: "2-3",
parentId: "2-1",
children: []
}
]
}
];
const getRelatedTreeFolders = (folders, selectedFolderId) => {
//** goes top to bottom
const recursiveChildCheck = (folder, id) => {
// THIS trial failed
// let foundNested = false;
// if (folder.id === id) {
// return true;
// }
// function recurse(folder) {
// if (!folder.hasOwnProperty("children") || folder.children.length === 0)
// return;
// for (var i = 0; i < folder.children.length; i++) {
// if (folder.children[i].id === id) {
// foundNested = true;
// break;
// } else {
// if (folder.children[i].children.length > 0) {
// recurse(folder.children[i].children);
// if (foundNested) {
// break;
// }
// }
// }
// }
// }
// recurse(folder);
// return foundNested;
const aChildHasIt =
folder.children.length > 0 && folder.children.some((f) => f.id === id);
if (aChildHasIt) return true;
let nestedChildHasIt = false;
/** The problem seems to be here */
folder.children.forEach((childFolder) => {
// Is using a forEach loop the correct way?
// ideally it seems there is a simple way to do a recursive .some on the dhildren...
childFolder.children.length>0 && recursiveChildCheck(childFolder, id)
});
if (nestedChildHasIt) return true;
folder.children && folder.children.forEach(recursiveChildCheck);
};
const treeSegment = folders.reduce((result = [], folder) => {
if (
folder.id === selectedFolderId ||
recursiveChildCheck(folder, selectedFolderId)
) {
result.push(folder);
}
return result;
}, []);
return treeSegment;
};
const selectedFolderId = "2-1";
const selectedFolderId1 = "2-2";
const selectedFolderId2 = "2-4";
const selectedFolderId3 = "2-3";
const selectedFolderId4 = "3-1";
const selectedFolderId5 = "1-1";
const selectedFolderId6 = "1-2";
console.log("parent");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId));
console.log("child");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId1));
console.log("grandchild"); // this fails
console.log(getRelatedTreeFolders(folderTree, selectedFolderId2));
console.log("sibling");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId3));
console.log("not found");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId4));
console.log("other parent");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId5));
console.log("other child");
console.log(getRelatedTreeFolders(folderTree, selectedFolderId6));
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
{/* <h2>{JSON.stringify(result)}</h2> */}
</div>
);
}
一些问题:
recursiveChildCheck
应该是 return 一个布尔值,但在某些情况下,没有任何内容 (undefined
) 是 returned,因为return
语句在以下表达式中丢失:folder.children && folder.children.forEach(recursiveChildCheck);
此外,在上面的表达式中,
&&
运算符的第二个操作数将永远不会被计算,因为folder.children
是一个数组,数组总是真实的,即使空数组。为了给第二个操作数一个机会,第一个操作数应该是folder.children.length > 0
但即使进行了该更正,第二个操作数 始终 的计算结果为
undefined
,因为这就是.forEach
returns 是设计使然。你应该在那里有一个方法调用 returns 一个布尔值,比如some
.nestedChildHasIt
在初始化后永远不会得到任何其他值,因此下面的return true
永远不会发生:if (nestedChildHasIt) return true;
您可能打算在前面的
forEach
循环中将nestedChildHasIt
设置为 true,但似乎您在这里有另一种方法来执行与其他forEach
相同的操作你最后的循环。
我认为你一直在努力解决的问题是你需要同时检查一个布尔条件(子树是否有 id
?) 和 你需要将子项过滤为符合此条件的子项,创建一个具有此唯一子项的新节点。
更正后的代码:
function getForestSegment(nodes, id) {
function recur(nodes) {
for (const node of nodes) {
if (node.id === id) return [node];
const children = recur(node.children);
if (children.length) return [{ ...node, children}];
}
return [];
}
return recur(nodes);
}
// Example from question:
const forest = [{id: "1-1",children: [{id: "1-2",parentId: "1-1",children: []}]},{id: "2-1",children: [{id: "2-2",parentId: "2-1",children: [{id: "2-4",parentId: "2-2",children: []}]},{id: "2-3",parentId: "2-1",children: []}]}];
for (const id of ["2-1", "2-2", "2-4", "2-3", "3-1", "1-1", "1-2"]) {
console.log(id);
console.log(getForestSegment(forest, id));
}