简体   繁体   English

树结构未按预期构建

[英]Tree structure not building as expected

I'm trying to write a function to create a tree from a given starting directory.我正在尝试编写 function 以从给定的起始目录创建树。 In other words, I choose a directory, and then the function maps absolutely everything in that particular directory.换句话说,我选择一个目录,然后 function 绝对映射该特定目录中的所有内容。 I've never done anything like this before, but I'm close to the expected output.我以前从未做过这样的事情,但我已经接近预期的 output。 However, I'm not sure where I'm going wrong.但是,我不确定我要去哪里错了。

Starting Directory起始目录

> Test Root
    > 1a
    > 1b
        > 2a
        > 2b
        > 2c
    > 1c
        > 2a
    > 1d
        > 2a
        > 2b
    > testfile.txt

Output Output

The first level is good to go.第一级好到go。 The second level is almost good to go, but for some reason it's duplicating the parent property and creating an additional nested object.第二级对 go 几乎很好,但由于某种原因,它复制了parent属性并创建了一个额外的嵌套 object。 It's also always inserting the type property.它也总是插入type属性。 I've tried removing properties in the constructor , but that output is just as bewildering.我试过删除constructor中的属性,但是 output 一样令人困惑。

{
  "parent": null,
  "path": "C:\\Users\\Anthony\\Desktop\\Test Root",
  "name": "Test Root",
  "kids": [
    {
      "parent": {
        "parent": "C:\\Users\\Anthony\\Desktop\\Test Root",
        "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1a",
        "name": "1a",
        "kids": []
      },
      "type": "fileType"
    },
    {
      "parent": {
        "parent": "C:\\Users\\Anthony\\Desktop\\Test Root",
        "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b",
        "name": "1b",
        "kids": [
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b\\2a",
              "name": "2a",
              "kids": []
            },
            "type": "fileType"
          },
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b\\2b",
              "name": "2b",
              "kids": []
            },
            "type": "fileType"
          },
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1b\\2c",
              "name": "2c",
              "kids": []
            },
            "type": "fileType"
          }
        ]
      },
      "type": "fileType"
    },
    {
      "parent": {
        "parent": "C:\\Users\\Anthony\\Desktop\\Test Root",
        "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1c",
        "name": "1c",
        "kids": [
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1c",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1c\\2a",
              "name": "2a",
              "kids": []
            },
            "type": "fileType"
          }
        ]
      },
      "type": "fileType"
    },
    {
      "parent": {
        "parent": "C:\\Users\\Anthony\\Desktop\\Test Root",
        "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1d",
        "name": "1d",
        "kids": [
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1d",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1d\\2a",
              "name": "2a",
              "kids": []
            },
            "type": "fileType"
          },
          {
            "parent": {
              "parent": "C:\\Users\\Anthony\\Desktop\\Test Root\\1d",
              "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\1d\\2b",
              "name": "2b",
              "kids": []
            },
            "type": "fileType"
          }
        ]
      },
      "type": "fileType"
    },
    {
      "parent": {
        "parent": "C:\\Users\\Anthony\\Desktop\\Test Root",
        "path": "C:\\Users\\Anthony\\Desktop\\Test Root\\testfile.txt",
        "name": "testfile.txt",
        "type": "fileType"
      },
      "type": "fileType"
    }
  ]
}

Function Function

async function createTree(root){
  const
    Node = class {
      constructor(parent, path, name, fifo){
        this.parent = parent
        this.path = path
        this.name = name
        fifo ? this.kids = [] : this.type = 'fileType'
      }
      addChild(parent, path, name, fifo){
        this.kids.push(new Node(parent, path, name, fifo))
      }
    },
    traverse = async function(node, path){
      const childPaths = await fsp.readdir(path)
      for (const childPath of childPaths){
        const
          name = childPath,
          stats = await fsp.stat(join(path, childPath))
        let
          fifo

        if (stats.isDirectory()) fifo = 1
        else if (stats.isFile()) fifo = 0

        const
          childNode = new Node(path, join(path, childPath), name, fifo)

        node.addChild(childNode)

        traverse(childNode, join(path, childPath))
      }
    },
    rootName = root.slice(-1) === '\\' ? root.slice(0,1) : root.slice(root.lastIndexOf('\\')+1),
    tree = new Node(null, root, rootName, 1)

    traverse(tree, root)

    setTimeout(function(){
      console.log(JSON.stringify(tree, null, 2))
    }, 2500)
}

I just realized my asynchronous functions aren't returning anything.我刚刚意识到我的异步函数没有返回任何东西。 I'm going to have to look over all of this tomorrow.明天我将不得不检查所有这些。

The problem is that you are passing in only the first argument to your addChild function here.问题是您在这里只将第一个参数传递给您的addChild function。

The addChild function expects 4 arguments to be provided. addChild function 预计将提供 4 个 arguments。 However:然而:

node.addChild(childNode)

// is approximately equivalent to:

addChild ( Node {...}, undefined, undefined, undefined)

You should be calling the function like this:您应该像这样调用 function:

node.addChild(childNode.path, childNode.path, childNode.name, childNode.fifo)

You're on the right path logically, approaching a nicely recursive solution, but I think the class is a bit overkill and far too object-oriented for a functional problem such as this.从逻辑上讲,您走在正确的道路上,接近了一个很好的递归解决方案,但我认为 class 有点矫枉过正,而且对于诸如此类的功能问题来说过于面向对象。 Here's a quick example of a more functional version which should give you the result you expect:这是一个功能更强大的版本的快速示例,它应该可以为您提供您期望的结果:

const nodePath = require('path');
const fs = require('fs');

/**
 * Supply an `fs` function and it will turn it into a promisified version
 * @param {Function} fn The function to promisify. This means you do not 
 * need the `fsp` library.
 */
function promisify (fn) {
  return (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => err ? reject(err) : resolve(data)));
};

// Create promisified versions of `fs.stat` and `fs.readdir`
const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);

function createDirectory (parent, path, name, kids) {
  return { parent, path, name, kids: kids || [] };
};

function createFile (parent, path, name) {
  return { parent, path, name, type: 'fileType' };
}

// The main recursive function.
async function createTree (parent, path) {
  let stats = await stat(path);

  if (stats.isDirectory()) {
    const children = await readdir(path);

    // Because each recursive call retruns a promise, we want to continue only when
    // all of them have resolved. So we use Promise.all for this.
    let child_nodes = await Promise.all(
      children.map(child => createTree(path, nodePath.join(path, child)))
    );

    // Create a directory node
    return createDirectory(parent, path, nodePath.basename(path), child_nodes);
  }

  // Create a file node
  return createFile(parent, path, nodePath.basename(path));
};


// Startup code, can use your own stuff here.
async function start () {
  let tree = await createTree(null, '/home/james/stackoverflow/58706769/Test Root');

  console.log(JSON.stringify(tree, null, 2));
}

start();

Running this file in Node, I get the following output:在 Node 中运行这个文件,我得到以下 output:

{
  "parent": null,
  "path": "/home/james/stackoverflow/58706769/Test Root",
  "name": "Test Root",
  "kids": [
    {
      "parent": "/home/james/stackoverflow/58706769/Test Root",
      "path": "/home/james/stackoverflow/58706769/Test Root/1a",
      "name": "1a",
      "kids": []
    },
    {
      "parent": "/home/james/stackoverflow/58706769/Test Root",
      "path": "/home/james/stackoverflow/58706769/Test Root/1b",
      "name": "1b",
      "kids": [
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1b",
          "path": "/home/james/stackoverflow/58706769/Test Root/1b/2a",
          "name": "2a",
          "kids": []
        },
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1b",
          "path": "/home/james/stackoverflow/58706769/Test Root/1b/2b",
          "name": "2b",
          "kids": []
        },
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1b",
          "path": "/home/james/stackoverflow/58706769/Test Root/1b/2c",
          "name": "2c",
          "kids": []
        }
      ]
    },
    {
      "parent": "/home/james/stackoverflow/58706769/Test Root",
      "path": "/home/james/stackoverflow/58706769/Test Root/1c",
      "name": "1c",
      "kids": [
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1c",
          "path": "/home/james/stackoverflow/58706769/Test Root/1c/2a",
          "name": "2a",
          "kids": []
        }
      ]
    },
    {
      "parent": "/home/james/stackoverflow/58706769/Test Root",
      "path": "/home/james/stackoverflow/58706769/Test Root/1d",
      "name": "1d",
      "kids": [
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1d",
          "path": "/home/james/stackoverflow/58706769/Test Root/1d/2a",
          "name": "2a",
          "kids": []
        },
        {
          "parent": "/home/james/stackoverflow/58706769/Test Root/1d",
          "path": "/home/james/stackoverflow/58706769/Test Root/1d/2b",
          "name": "2b",
          "kids": []
        }
      ]
    },
    {
      "parent": "/home/james/stackoverflow/58706769/Test Root",
      "path": "/home/james/stackoverflow/58706769/Test Root/testfile.txt",
      "name": "testfile.txt",
      "type": "fileType"
    }
  ]
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM