Цикл структуры файловой системы в моем объекте, чтобы получить все файлы
Я получаю объект 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 ответа
Я был занят игрой с вашим оригинальным вопросом и получил это работать:
goToDeepestPoint(json);
function goToDeepestPoint(node) {
if (node.is_dir)
node.children.forEach(function (child) {
goToDeepestPoint(child);
});
else
return out(node.path);
}
Может не подходить в свете ваших правок, но позор тратить их впустую!
Я поделюсь своим ответом, потому что он имеет отношение к тому, над чем я сейчас работаю - он требует более функционального подхода, потому что это именно то, что я изучаю
Постоянные итераторы
Итераторы с состоянием в JavaScript делают меня грустным, поэтому мы можем реализовать постоянный интерфейс итератора, используя наш собственный Yield
а также Return
типы. Memo
Тип используется, но это просто деталь оптимизации.
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
Теперь, если необходимо создать адаптер для взаимодействия с собственными генераторами 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)
Конечно, ответ неполон без демонстрации рабочего кода
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)
}
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>
Рабочий раствор:
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";
}