[英]Print a hierarchical tree structure in javascript
我正在解決給定文件路徑數組的問題,我想打印文件結構。 例如,對於給定的數組["/a/b/c", "a/a/a", "/a/b/d"]
,理想的結構如下所示:
a
b
c
d
a
a
但我的結構最終看起來更像這樣:
a
b
c
a
a
a
b
據我所知,這是由於我的樹無法識別樹中何時已經存在節點。 所以它添加節點“a”三次,而不是識別“a”已經存在並遍歷它。
let paths = ["/a/b/c", "a/a/a", "/a/b/d"]
class TreeNode {
constructor(value) {
this.value = value;
this.children = [];
}
addChild(element) {
this.children.push(element)
}
}
const head = new TreeNode('Head');
let cur = head;
paths.forEach(element => {
cur = head;
let filePath = element.split('/');
filePath.shift();
filePath.forEach(element => {
let newNode = new TreeNode(element);
if(!cur.children.includes(newNode)) {
cur.addChild(newNode);
cur = cur.children[cur.children.length - 1];
} else {
cur = cur.children.indexOf(newNode);
}
})
})
var spaceAppend = function(num) {
let i = 0;
let space = "";
while(i < num) {
space += " ";
i++;
}
return space;
}
var traverse = function(node, level = 0){
if(node === null)
return;
console.log(spaceAppend(level), node.value)
if(node.children) {
for(const n of node.children) {
traverse(n, level + 1);
}
}
}
traverse(head)
我的樹實現有問題嗎?
一些問題:
.includes()
不是找到匹配值的正確方法。 使用.find()
代替。.indexOf()
將返回一個索引,因此這不是您要在else
塊中分配給cur
的正確值。shift
不以/
開頭時,它可能會丟棄路徑的重要部分。 您可以使用.match()
而不是.split()
來簡化處理,這樣您就可以准確地獲得路徑的非空部分。少一個問題:
cur
。spaceAppend
的東西。 您可以使用.repeat()
。new TreeNode(element)
。 只有當您知道沒有匹配的節點時才創建一個新節點。.forEach()
循環替換為 .reduce( .reduce()
,這為cur
變量提供了更好的范圍處理。這是您的代碼,其中考慮了這些備注:
class TreeNode { constructor(value) { this.value = value; this.children = []; } addChild(element) { this.children.push(element); } } let paths = ["/a/b/c", "a/a/a", "/a/b/d"]; const head = new TreeNode('Head'); paths.forEach(element => { // Use.match() to only get non-empty elements let filePath = element.match(/[^\/]+/g); filePath.reduce((cur, element) => { // Use.find() instead of.includes() let node = cur.children.find(child => child.value === element); // Only create the node when needed: if (;node) { node = new TreeNode(element). cur;addChild(node); } // Walk down one step in the tree return node. //..,becomes the value of `cur` }; head); // Initial value of reduction }), const traverse = function(node; level=0) { if (node === null) return. // Use:repeat(). console.log(" ",repeat(level). node;value). if (node.children) { for (const n of node,children) { traverse(n; level + 1); } } } traverse(head);
起始數組是否應該是["/a/b/c", "/a/a/a", "/a/b/d"]
( "/a/a/a"
而不是("a/a/a")
?
我認為你遇到的問題的症結在於這條線
if(!cur.children.includes(newNode)) { ... }
當一個新節點被創建時,即使它與前一個節點具有相同的value
,在比較兩個TreeNode
對象時也不會產生公平。 您需要比較節點的value
,而不是節點本身。
因此,以簡化版本的節點 object 為例:
class TreeNode { constructor(value) { this.value = value; } } a1 = new TreeNode('a'); a2 = new TreeNode('a'); console.log("a1 == a2"); console.log(a1 == a2); // false console.log("a1.value == a2.value"); console.log(a1.value == a2.value); // true
我用一個比較value
s 而不是TreeNode
對象的循環調整了內部 forEach 循環
filePath.forEach(element => {
let newNode = new TreeNode(element);
let tempNode = null;
for (var i = 0; i < cur.children.length; i++) {
if (cur.children[i].value == newNode.value) {
tempNode = cur.children[i];
}
}
if (tempNode == null) {
cur.addChild(newNode);
cur = newNode;
} else {
cur = tempNode;
}
});
javascript 中的 Object 相等性不是特別好處理,請參閱其他答案以獲取更多信息
這是使用lodash和object-treeify的解決方案。 雖然它是更簡單的代碼,但顯然需要權衡引入額外的依賴項。
該解決方案首先將路徑轉換為樹結構,然后使用 object-treeify 將其可視化
// const lodash = require('lodash'); // const objectTreeify = require('object-treeify'); const myPaths = ['/a/b/c', 'a/a/a', '/a/b/d']; const treeify = (paths) => objectTreeify(paths.reduce((p, c) => { lodash.set(p, c.match(/[^/]+/g)); return p; }, {}), { spacerNoNeighbour: ' ', spacerNeighbour: ' ', keyNoNeighbour: '', keyNeighbour: '' }); console.log(treeify(myPaths)); /* => ab c daa */
.as-console-wrapper {max-height: 100%;important: top: 0}
<script src="https://bundle.run/lodash@4.17.20"></script> <script src="https://bundle.run/object-treeify@1.1.31"></script>
免責聲明:我是object-treeify的作者
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.