我使用Map 创建了一个具有自定义树节点格式的示例代码,打印函数是一个生成器函数,用于逐行获取树的路径。
// Node
class NodePath {
constructor(e) {
this.isFolder = e.isFolder;
this.name = e.name;
this.childs = new Map();
}
}
// Make path tree
function makePathsTree(paths) {
const treeRoot = new NodePath({isFolder: true, name: "*"});
for (const path of paths) {
// Set current post as root
let curPos = treeRoot;
// For each part
const parts = path.split("/");
while (parts.length) {
// Get cur
const curPart = parts.shift();
// Get child node, create if not exists
let childNode = curPos.childs.get(curPart);
if (!childNode) {
childNode = new NodePath({
isFolder: !!parts.length,
name: curPart,
});
curPos.childs.set(curPart, childNode)
}
// Update cur post to child node
curPos = childNode;
}
}
// Return tree
return treeRoot;
}
// Generator function prevent huge large file system strings
function *printPathsTree(node, offset = 0, prev = "") {
// Offset str
const offsetStr = " ".repeat(offset);
// Is folder
if (!node.isFolder) {
yield `${offsetStr}${prev}${node.name}`;
return;
}
// If one child and is folder, merge paths
if (node.childs.size === 1) {
const child = node.childs.values().next().value;
if (child.isFolder === true) {
for (const childData of printPathsTree(child, offset, `${prev}${node.name}/`)) {
yield childData;
}
return;
}
}
// Print node name
yield `${offsetStr}${prev}${node.name}`;
// For each child, print data inside
for (const child of node.childs.values()) {
for (const childData of printPathsTree(child, offset + prev.length, "|---")) {
yield childData;
}
}
}
// == CODE ==
console.log("WITH ROOT:");
const tree = makePathsTree([
"A/B/C/D/file1.txt",
"A/B/C/D/file2.txt",
"A/B/D/E/file2.txt",
"A/B/D/G/file3.txt",
"A/B/D/G/file4.txt",
]);
// Print tree step by step
for(const nodePath of printPathsTree(tree)) {
console.log(nodePath);
}
// Print with A as root
console.log("\nA AS ROOT:");
for(const nodePath of printPathsTree(tree.childs.values().next().value)) {
// for(const nodePath of printPathsTree(tree.childs.get("A"))) { // same
console.log(nodePath);
}
输出:
WITH ROOT:
*/A/B
|---C/D
|---file1.txt
|---file2.txt
|---D
|---E
|---file2.txt
|---G
|---file3.txt
|---file4.txt
A AS ROOT:
A/B
|---C/D
|---file1.txt
|---file2.txt
|---D
|---E
|---file2.txt
|---G
|---file3.txt
|---file4.txt