简体   繁体   English

尾递归JSON构造函数

[英]Tail recursive JSON constructor

I have a directory structure from NPM package ' directory-tree ' that I would like to flatten into a simpler nested structure. 我有一个NPM包' directory-tree '的目录结构,我想把它压缩成一个更简单的嵌套结构。 I want a tail recursive solution to convert the first object into the second, but I'm having trouble wrapping my head around how to construct it. 我想要一个尾递归解决方案将第一个对象转换为第二个对象,但是我无法绕过如何构造它。

Of course the primary conditional is whether or not a 'node' in the first structure is a 'file' or a 'directory'. 当然,主要条件是第一个结构中的“节点”是“文件”还是“目录”。 If it's a file, we simply want the basename of the file to key the relative path. 如果它是一个文件,我们只需要文件的基本名称来键入相对路径。 However, if it's a directory, we want the basename of the directory to key an object and recurse down frome there. 但是,如果它是一个目录,我们希望目录的基本名称键入一个对象并在那里递归。

I'll use their example to illustrate the structure: 我将用他们的例子来说明结构:

 { "path": "photos", "name": "photos", "size": 600, "type": "directory", "children": [ { "path": "photos/summer", "name": "summer", "size": 400, "type": "directory", "children": [ { "path": "photos/summer/june", "name": "june", "size": 400, "type": "directory", "children": [ { "path": "photos/summer/june/windsurf.jpg", "name": "windsurf.jpg", "size": 400, "type": "file", "extension": ".jpg" } ] } ] }, { "path": "photos/winter", "name": "winter", "size": 200, "type": "directory", "children": [ { "path": "photos/winter/january", "name": "january", "size": 200, "type": "directory", "children": [ { "path": "photos/winter/january/ski.png", "name": "ski.png", "size": 100, "type": "file", "extension": ".png" }, { "path": "photos/winter/january/snowboard.jpg", "name": "snowboard.jpg", "size": 100, "type": "file", "extension": ".jpg" } ] } ] } ] } 

I'd like the final structure to be much simpler. 我希望最终的结构更加简单。 Something like the following: 类似于以下内容:

 { "photos": { "summer": { "june": { "windsurf.jpg": "photos/summer/june/windsurf.jpg" } }, "winter": { "january": { "ski.png": "photos/winter/january/ski.png", "snowboard.jpg": "photos/winter/january/snowboard.jpg" } } } } 

We can convert a depth-first search to tail-recursion for your case. 我们可以为您的案例将深度优先搜索转换为尾递归。

 let testObj = { "path": "photos", "name": "photos", "size": 600, "type": "directory", "children": [ { "path": "photos/summer", "name": "summer", "size": 400, "type": "directory", "children": [ { "path": "photos/summer/june", "name": "june", "size": 400, "type": "directory", "children": [ { "path": "photos/summer/june/windsurf.jpg", "name": "windsurf.jpg", "size": 400, "type": "file", "extension": ".jpg" } ] } ] }, { "path": "photos/winter", "name": "winter", "size": 200, "type": "directory", "children": [ { "path": "photos/winter/january", "name": "january", "size": 200, "type": "directory", "children": [ { "path": "photos/winter/january/ski.png", "name": "ski.png", "size": 100, "type": "file", "extension": ".png" }, { "path": "photos/winter/january/snowboard.jpg", "name": "snowboard.jpg", "size": 100, "type": "file", "extension": ".jpg" } ] } ] } ] }; function tailRecurse(stack, result){ if (!stack.length) return result; // stack will contain // the next object to examine [obj, ref] = stack.pop(); if (obj.type == 'file'){ ref[obj.name] = obj.path; } else if (obj.type == 'directory'){ ref[obj.name] = {}; for (let child of obj.children) stack.push([child, ref[obj.name]]); } return tailRecurse(stack, result); } // Initialise let _result = {}; let _stack = [[testObj, _result]]; console.log(tailRecurse(_stack, _result)); 

function copyNode(node, result = {}){
   if(node.type === "directory"){
      const folder = result[node.name] = {};
      for(const sub of node.children)
           copyNode(sub, folder);

  } else {
      result[node.name] = node.path;
  }
  return result;
}

This is a simple recursive approach, this is not tail call recursive as it is very difficult ( = not worth it ) to traverse a tree with only one tail call. 这是一种简单的递归方法,这不是尾调用递归,因为仅使用一个尾调用遍历树是非常困难的(=不值得)。

You could take a recursive approach by chekcing the type. 你可以通过chekcing类型采取递归方法。

For 'directory' take an object and iterate the children. 对于'directory'取一个对象并迭代子节点。

Otherwise assign the path to the key with the given name. 否则,使用给定名称指定密钥的路径。

 function fn(source, target) { if (source.type === 'directory') { target[source.name] = {}; (source.children || []).forEach(o => fn(o, target[source.name])); } else { target[source.name] = source.path; } } var source = { path: "photos", name: "photos", size: 600, type: "directory", children: [{ path: "photos/summer", name: "summer", size: 400, type: "directory", children: [{ path: "photos/summer/june", name: "june", size: 400, type: "directory", children: [{ path: "photos/summer/june/windsurf.jpg", name: "windsurf.jpg", size: 400, type: "file", extension: ".jpg" }] }] }, { path: "photos/winter", name: "winter", size: 200, type: "directory", children: [{ path: "photos/winter/january", name: "january", size: 200, type: "directory", children: [{ path: "photos/winter/january/ski.png", name: "ski.png", size: 100, type: "file", extension: ".png" }, { path: "photos/winter/january/snowboard.jpg", name: "snowboard.jpg", size: 100, type: "file", extension: ".jpg" }] }] }] }, target = {}; fn(source, target); console.log(target); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

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

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