循环到我的对象中的文件系统结构以获取所有文件

时间:2017-08-08 10:29:31

标签: javascript recursion

我从我的服务器获取一个Javascript对象,它描述了一个文件系统。现在我想获得系统中所有文件的路径,例如树的端点。

文件结构示例:

└── pages
    └── services
        └── project            
            │── headline
            │── test
            │   └── text
            │   └── picture 
            │── text

可读JSON:

{
"path":"/pages/services/project",
"is_dir":true,
"children":[
  {
     "path":"/pages/services/project/headline",
     "is_dir":false,
     "children":[

     ]
  },
  {
     "path":"/pages/services/project/text",
     "is_dir":false,
     "children":[

     ]
  },
  {
     "path":"/pages/services/project/test/",
     "is_dir":true,
     "children":[
        {
           "path":"/pages/services/project/test/text",
           "is_dir":false,
           "children":[

           ]
        },
        {
           "path":"/pages/services/project/test/picture",
           "is_dir":false,
           "children":[

           ]
        }
     ]
  }

]      }

预期产出:

/pages/services/project/headline
/pages/services/project/text
/pages/services/project/test/text
/pages/services/project/test/picture

我在递归时玩了一下,做了一个哑的功能,当一个目录只有一个孩子时。我的问题是我无法掌握处理更多孩子的方法。有没有办法迭代每个孩子?

这是我的代码:

var json = {"path":"/pages/services/project", "is_dir":true, "children":[{"path":"/pages/services/project/headline","is_dir":false,"children":[]},{"path":"/pages/services/project/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/","is_dir":true,"children":[{"path":"/pages/services/project/test/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/picture","is_dir":false,"children":[]}]}]};

json.children.forEach(function (child) {
	out(goToDeepestPoint(child).path);
});



function goToDeepestPoint(node) {
    if (node.is_dir)
        return goToDeepestPoint(node.children[0]);
    else 
        return node;
}

function out()
{
    var args = Array.prototype.slice.call(arguments, 0);
    document.getElementById('output').innerHTML += args.join(" ") + "\n";
}
<pre id="output"></pre>

4 个答案:

答案 0 :(得分:1)

工作解决方案:

var json = {"path":"/pages/services/project", "is_dir":true, "children":[{"path":"/pages/services/project/headline","is_dir":false,"children":[]},{"path":"/pages/services/project/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/","is_dir":true,"children":[{"path":"/pages/services/project/test/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/picture","is_dir":false,"children":[]}]}]};

json.children.forEach(function (child) {
    goToDeepestPoint(child);
});



function goToDeepestPoint(node) {
    if (node.is_dir){
      for(var i=0;i<node.children.length;i++){
        goToDeepestPoint(node.children[i]);
      }
    }        
    else {
        out(node.path);
    }
}

function out()
{
    var args = Array.prototype.slice.call(arguments, 0);
    document.getElementById('output').innerHTML += args.join(" ") + "\n";
}

答案 1 :(得分:1)

var json = {"path":"/pages/services/project", "is_dir":true, "children":[{"path":"/pages/services/project/headline","is_dir":false,"children":[]},{"path":"/pages/services/project/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/","is_dir":true,"children":[{"path":"/pages/services/project/test/text","is_dir":false,"children":[]},
{"path":"/pages/services/project/test/picture","is_dir":false,"children":[]}]}]};

function getPaths(obj){
    let foundPaths = [];
    if(obj.children.length > 0){
        obj.children.forEach(function (element){
           let childPaths = getPaths(element);
           foundPaths = foundPaths.concat(childPaths);
        });
        return foundPaths;
   } else {
      foundPaths.push(obj.path);
      return foundPaths;
   }
}

let paths = getPaths(json);

document.getElementById('output').innerHTML += paths.join("\n");
<pre id="output"></pre>

答案 2 :(得分:0)

我正在忙着玩你原来的问题并开始工作:

goToDeepestPoint(json);

function goToDeepestPoint(node) {
    if (node.is_dir)
        node.children.forEach(function (child) {
    goToDeepestPoint(child);
});
    else 
        return out(node.path);
}

根据你的编辑可能不合适,但遗憾的是浪费它!

答案 3 :(得分:0)

我会分享我的答案,因为它与我目前正在处理的事情有关 - 它需要一种更具功能性的方法,因为这恰好是我所做的事情。我一直在学习

持久性迭代器

JavaScript的有状态迭代器让我感到难过,因此我们可以使用自己的YieldReturn类型实现持久性迭代器接口。使用了Memo类型,但这只是一个优化细节。

&#13;
&#13;
const Memo = (f, memo) => () =>
  memo === undefined
    ? (memo = f (), memo)
    : memo

const Yield = (value, next = Return) =>
  ({ done: false, value, next: Memo (next) })
  
const Return = value =>
  ({ done: true, value })
  
// example use
const ArrayIterator = (xs = []) =>
  xs.length === 0
    ? Return ()
    : Yield (xs [0], () => ArrayIterator (xs.slice (1)))
    
const it =
  ArrayIterator ([1,2,3])

console.log (it.value) // 1
console.log (it.value) // 1
console.log (it.next () .value) // 2
console.log (it.next () .value) // 2
&#13;
&#13;
&#13;

现在,如果需要创建适配器以与JavaScript的本机生成器进行互操作,我们可以创建Generator类型

不可否认,这不是非常有趣,但确实展示了必要的功能

const Generator = function* (it = Return ())
  {
    while (it.done === false)
      (yield it.value, it = it.next ())
    return it.value
  }

Array.from (Generator (ArrayIterator ([1,2,3])))
// => [1,2,3]

我们的持久迭代器为更多令人兴奋的事情打开了大门。

const MappedIterator = (f = x => x, it = Return ()) =>
  it.done
    ? Return ()
    : Yield (f (it.value), () => MappedIterator (f, it.next ()))

const ConcatIterator = (x = Return (), y = Return) =>
  x.done
    ? y ()
    : Yield (x.value, () => ConcatIterator (x.next (), y))

const it =
  MappedIterator (x => x * x, ArrayIterator ([1,2,3]))

Array.from (Generator (it))                      // => [ 1, 4, 9 ]
Array.from (Generator (ConcatIterator (it, it))) // => [ 1, 4, 9, 1, 4, 9 ]

纯粹表达

我们的持久迭代器为我们提供了一种表达数据结构可能复杂遍历的简洁方法。这是我们将树迭代器编写为纯表达式的一种方法

const FlatMappedIterator = (f, it = Return ()) =>
  it.done
    ? Return ()
    : ConcatIterator (f (it.value), () => FlatMappedIterator (f, it.next ()))

const MyTreeIterator = node =>
  node === undefined
    ? Return ()
    : node.is_dir
      ? FlatMappedIterator (MyTreeIterator, ArrayIterator (node.children))
      : Yield (node.path)

当然,如果没有工作代码的演示,答案是不完整的

&#13;
&#13;
const Memo = (f, memo) => () =>
  memo === undefined
    ? (memo = f (), memo)
    : memo

const Yield = (value, next = Return) =>
  ({ done: false, value, next: Memo (next) })
  
const Return = value =>
  ({ done: true, value })

// -------------------------------------------------------------------
const ArrayIterator = (xs = []) =>
  xs.length === 0
    ? Return ()
    : Yield (xs [0], () => ArrayIterator (xs.slice (1)))
    
const ConcatIterator = (x = Return (), y = Return) =>
  x.done
    ? y ()
    : Yield (x.value, () => ConcatIterator (x.next (), y))
    
const FlatMappedIterator = (f, it = Return ()) =>
  it.done
    ? Return ()
    : ConcatIterator (f (it.value), () => FlatMappedIterator (f, it.next ()))

const Generator = function* (it = Return ())
  {
    while (it.done === false)
      (yield it.value, it = it.next ())
    return it.value
  }
  
// -------------------------------------------------------------------
const MyTreeIterator = node =>
  node === undefined
    ? Return ()
    : node.is_dir
      ? FlatMappedIterator (MyTreeIterator, ArrayIterator (node.children))
      : Yield (node.path)

const data =
  {path:'/pages/services/project', is_dir:true, children:[
    {path:'/pages/services/project/headline',is_dir:false,children:[]},
    {path:'/pages/services/project/text',is_dir:false,children:[]},
    {path:'/pages/services/project/test/',is_dir:true,children:[
      {path:'/pages/services/project/test/text',is_dir:false,children:[]},
      {path:'/pages/services/project/test/picture',is_dir:false,children:[]}
    ]}
  ]}

// -------------------------------------------------------------------
// example use of generator around our custom persistent iterator
for (const path of Generator (MyTreeIterator (data)))
  {
    const elem = document.createElement ('p')
    elem.textContent = path
    document.body.appendChild (elem)
  }
&#13;
&#13;
&#13;