簡體   English   中英

打印 javascript 中的層次樹結構

[英]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
  • JavaScript 有一個原生的 function 用於類似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;
    }
});

codepen 上的完整代碼片段

javascript 中的 Object 相等性不是特別好處理,請參閱其他答案以獲取更多信息

這是使用lodashobject-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM