Javascript 嵌套树结构数据生成

Javascript 嵌套树结构数据生成,javascript,angular,loops,lodash,angular6,Javascript,Angular,Loops,Lodash,Angular6,请直接回答我的英语和写作问题,我有一个json数据数组,我正试图将它做成嵌套的树结构,但没有成功,希望有人能帮助我。 我的示例数据: [ { "id" : 1, "name" : "Abc", "path" : "/", "type" : "folder" }, { "id" : 2, "name" : "Xyz", "path" : "/Abc/", "type" : "folder" }, { "id" : 3, "name" : "Pqr", "

请直接回答我的英语和写作问题,我有一个json数据数组,我正试图将它做成嵌套的树结构,但没有成功,希望有人能帮助我。 我的示例数据:

[ {
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 2,
  "name" : "Xyz",
  "path" : "/Abc/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}, {
  "id" : 4,
  "name" : "Zap", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "folder"
 },{
  "id" : 5,
  "name" : "file1", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 6,
  "name" : "file2", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 7,
  "name" : "file3", 
  "path" : "/Abc/Xyz/",
  "type" : "file"
},{
  "id" : 8,
  "name" : "file4", 
  "path" : "/Abc/Xyz/Pqr/Zap/",
  "type" : "file"
}
很抱歉,我正在使用一些大数据来正确理解,现在我想要的嵌套格式是这样的

[{
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
  "Children":[{
    "id" : 2,
    "name" : "Xyz",
    "path" : "/Abc/",
    "type" : "folder",
    "Children":[{
           "id" : 3,
           "name" : "Pqr",
           "path" : "/Abc/Xyz/",
           "type" : "folder",
           "Children": [{
                   "id" : 4,
                    "name" : "Zap", 
                    "path" : "/Abc/Xyz/Pqr/",
                    "type" : "folder",
                    "Children":[{
                            "id" : 8,
                             "name" : "file4", 
                              "path" : "/Abc/Xyz/Pqr/Zap/",
                             "type" : "file"
                         }]
                   },{
                    "id" : 5,
                    "name" : "file1", 
                    "path" : "/Abc/Xyz/Pqr/",
                    "type" : "file"
                   },{
                      "id" : 6,
                      "name" : "file2", 
                      "path" : "/Abc/Xyz/Pqr/",
                      "type" : "file"
             }]
         },{
           "id" : 7,
           "name" : "file3", 
           "path" : "/Abc/Xyz/", 
           "type" : "file"
      }]
 }]
 }
现在,与lodash一起使用的登录如下:datas=allData

 const dd= [];
_.forEach(datas, function(v, k) {
  let cc = {};
    if (v.type == 'folder') {

      cc['children'] = _.filter(datas, function(v1, k1) {
        if (v.path + v.name + '/' == v1.path || v1.path.startsWith(v.path + v.name + '/')) {
          return v1;
        }
      });
      cc['name'] = v.name;
      cc['type'] = v.type;
      cc['id'] = v.id;
      cc['path'] = v.path;
      dd.push(cc);
    } else {
      if (v.path == '/') {
        dd.push(cc);
      }
    }

});
但并没有得到正确的答案,我知道问题太长了,但请帮我解决这个问题。

哇!那很有趣

const data = [ {
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 2,
  "name" : "Xyz",
  "path" : "/Abc/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}, {
  "id" : 4,
  "name" : "Zap", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "folder"
 },{
  "id" : 5,
  "name" : "file1", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 6,
  "name" : "file2", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 7,
  "name" : "file3", 
  "path" : "/Abc/Xyz/",
  "type" : "file"
},{
  "id" : 8,
  "name" : "file4", 
  "path" : "/Abc/Xyz/Pqr/Zap/",
  "type" : "file"
}]

const pathPartRegex = /.*?\//g;
const tree = _.reduce(data, (result, value) => {
    const pathParts = value.path.match(pathPartRegex);
    let node = result;
    let path = "";

    // Go down through tree until last path part
    const notLastPart = pathParts.splice(0, pathParts.length - 1);
    for (const pathPart of notLastPart) {
        path += pathPart;
        const existingNode = node.children 
                                ? node.children.find(item => item.path === path)
                                : node.find(item => item.path === path);
        if (existingNode) {
            node = existingNode
        } else {
            // If we need to traverse over a path that doesn't exist, just create it
            // See notes 
            const newNode = {
                path: path,
                children: []
            };

            // The root element is just an array, and doesn't have a children property
            if (node.children) {
                node.children.push(newNode);
            } else {
                node.push(newNode);
            }
            node = newNode;
        }
    }

    // Add new node
    const newNode = {
        id: value.id,
        name: value.name,
        type: value.type,
        path: value.path,
        children: []
    };

    // The root element is just an array, and doesn't have a children property
    if (node.children) {
        node.children.push(newNode);
    } else {
        node.push(newNode);
    }

    return result;
}, []);

通过RunKit()进行测试


注:

示例数据集不包括如何处理根本未定义“父”路径的情况:

const data = [{
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}];
也不是在子路径之后定义“父”路径的情况:

const data = [{
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}, {
  "id" : 2,
  "name" : "Xyz",
  "path" : "/Abc/",
  "type" : "folder"
}];
我编写的代码将处理这些问题,但可能会创建没有
id
属性的节点。如果您需要处理这样的情况,您可以事先修复输入数据,也可以修改此代码来处理这些情况。

哇!那很有趣

const data = [ {
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 2,
  "name" : "Xyz",
  "path" : "/Abc/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}, {
  "id" : 4,
  "name" : "Zap", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "folder"
 },{
  "id" : 5,
  "name" : "file1", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 6,
  "name" : "file2", 
  "path" : "/Abc/Xyz/Pqr/",
  "type" : "file"
},{
  "id" : 7,
  "name" : "file3", 
  "path" : "/Abc/Xyz/",
  "type" : "file"
},{
  "id" : 8,
  "name" : "file4", 
  "path" : "/Abc/Xyz/Pqr/Zap/",
  "type" : "file"
}]

const pathPartRegex = /.*?\//g;
const tree = _.reduce(data, (result, value) => {
    const pathParts = value.path.match(pathPartRegex);
    let node = result;
    let path = "";

    // Go down through tree until last path part
    const notLastPart = pathParts.splice(0, pathParts.length - 1);
    for (const pathPart of notLastPart) {
        path += pathPart;
        const existingNode = node.children 
                                ? node.children.find(item => item.path === path)
                                : node.find(item => item.path === path);
        if (existingNode) {
            node = existingNode
        } else {
            // If we need to traverse over a path that doesn't exist, just create it
            // See notes 
            const newNode = {
                path: path,
                children: []
            };

            // The root element is just an array, and doesn't have a children property
            if (node.children) {
                node.children.push(newNode);
            } else {
                node.push(newNode);
            }
            node = newNode;
        }
    }

    // Add new node
    const newNode = {
        id: value.id,
        name: value.name,
        type: value.type,
        path: value.path,
        children: []
    };

    // The root element is just an array, and doesn't have a children property
    if (node.children) {
        node.children.push(newNode);
    } else {
        node.push(newNode);
    }

    return result;
}, []);

通过RunKit()进行测试


注:

示例数据集不包括如何处理根本未定义“父”路径的情况:

const data = [{
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}];
也不是在子路径之后定义“父”路径的情况:

const data = [{
  "id" : 1,
  "name" : "Abc",
  "path" : "/",
  "type" : "folder"
}, {
  "id" : 3,
  "name" : "Pqr",
  "path" : "/Abc/Xyz/",
  "type" : "folder"
}, {
  "id" : 2,
  "name" : "Xyz",
  "path" : "/Abc/",
  "type" : "folder"
}];

我编写的代码将处理这些问题,但可能会创建没有
id
属性的节点。如果您需要处理这样的情况,您可以事先修复输入数据,也可以修改此代码来处理这些情况。

我也得到了如下答案:

const sts=_.memoize(function(){ return []; });
const result = _.filter(folderdata, function(item){
  let parentName = '';
  if(item.path != '/')parentName = item.path;
  item.children = sts(item.path+item.name+'/');
  if (item.type == 'folder') return !(parentName && sts(parentName).push(item));
});

我得到的答案是这样的:

const sts=_.memoize(function(){ return []; });
const result = _.filter(folderdata, function(item){
  let parentName = '';
  if(item.path != '/')parentName = item.path;
  item.children = sts(item.path+item.name+'/');
  if (item.type == 'folder') return !(parentName && sts(parentName).push(item));
});

这是一致的,你知道吗?它总是有id、路径、名称、类型和子项,如果有一致的内容,知道吗?它总是有id、路径、名称、类型和子项,如果有什么真的很好的答案,最后只有一个问题您返回结果,但您没有为结果分配任何内容,除了每次更新的方式?我还在下面分享了一个解决方案。@user3458271本质上,这就是reduce的工作原理。它以空数组的初始值开始(第三个参数)每次迭代返回的值都会传递给nextyo,这真是一个很好的答案。最后只回答了一个问题。您返回的是结果,但您没有为结果分配任何内容,只是每次更新的方式。下面我还分享了一个解决方案。@user3458271本质上,这就是reduce的工作方式。它以一个空数组的初始值(第三个参数)开始,并将每次迭代返回的值传递给下一个数组