从文件路径构建树
Build a tree from file paths
我试图从文件路径创建一个树视图,它可以动态地添加和删除,例如:
A/B/C/D/file1.txt
A/B/D/E/file2.txt
A/B/D/G/file3.txt
A/B/D/G/file4.txt
然而,我的树有一个要求,没有子项(文件)的路径应该折叠在一个节点中。对于上面的路径,它将产生:
A/B
|---C/D
file1.txt
|---D
|---E
| file2.txt
|---G
file3.txt
file4.txt
任何想法吗?创建树很容易,但我无法克服这个额外条件……我假设我必须使用某种递归,当我添加项和打破路径时,我们发现某个路径有更多的子路径(然后做同样的递归?)我要不要试试?当同一路径可以有多个文件时,它会工作吗?谢谢!
让我们从一个简单的解决方案开始,打印树的实际情况:
function browseTree(node)
{
// ...print node...
// Visit recursively the children nodes:
for (var child: node.children)
{
browseTree(child);
}
}
现在,让我们将其修改为"缩短"单个文件夹路径:
function browseTree(node)
{
// Before printing, accumulate as many straight folders as possible:
var nodeName=node.name
while (hasJustOneFolder(node))
{
// This loop steps deeper in the tree:
node=node.children[0]
nodeName+="/"+node.name;
}
// ...print node...
// Last, visit recursively the non-unique children nodes:
for (var child: node.children)
{
browseTree(child);
}
}
function hasJustOneFolder(node)
{
return node.children.length==1 && node.children[0].isFolder();
}
考虑到您的需求,似乎在C中添加一个新文件并不意味着要进行递归操作。
如果您将file5.txt
添加到文件夹C,则必须将C/D
转换为具有2个子节点的节点C
: file5.txt
和一个名为D
的新节点。D
将具有与旧节点C/D
相同的子节点。然后可以擦除节点C/D
。
然而,这不会影响节点A/B
,因为文件夹A仍然只有一个文件夹(B)作为子文件夹。因此,您可以仅通过局部更改来解决问题。
我用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
您可以通过在前导路径名上递归分组,然后合并父-子名称(如果父级只有一个子级)来构建树:
var paths = ["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"]
function merge_paths(paths){
var d = {};
var new_d = {}
for (var [a, ...b] of paths){
d[a] = (a in d) ? [...d[a], b] : [b]
}
for (var i of Object.keys(d)){
if (d[i].every(x => x.length === 1)){
new_d[i] = d[i].map(x => x[0]);
}
else{
var k = merge_paths(d[i])
if (Object.keys(k).length > 1){
new_d[i] = k
}
else{
new_d[`${i}/${Object.keys(k)[0]}`] = k[Object.keys(k)[0]]
}
}
}
return new_d;
}
var result = merge_paths(paths.map(x => x.split('/')))
console.log(result)
相关文章:
- 我应该如何从xml文件构建一个javascript页面
- 如何在DOM元素上按类型构建此函数
- Javascript:使用绝对路径设置img src
- Yeoman构建注释标记中的动态路径
- 当连接在一起时,如何使用两个部分构建 JSON 对象,生成正确的 JSON 数据路径
- 在 jquery 中为内联 css 构建图像路径的最佳方法
- 全栈应用程序Gulp构建的输出/路径/结构策略
- 使用CDN的Require.js构建(r.js)jQuery不是't链接到良好的jQuery路径
- 根据路径字符串构建嵌套文件夹结构
- 避免重复“;路径”;RequireJS主文件和r.js构建文件中的配置
- 从物化路径构建JSON树
- 以零碎的方式构建一个拉斐尔路径对象
- 如何在构建脚本中添加CDN url以要求路径
- 在JavaScript中构建到深度对象树的路径
- 为URI构建一个路径树
- 我怎么能加载一个url(路径)的图片或其他在您的构建(prod)与webpack的文件
- Js在属性分配中构建对象路径
- 用变量构建对象路径
- 如何通过Javascript从两个选择/选项id构建图像名称/路径
- 如何用绝对路径构建index.html参考资产