Reputation: 350
I'm trying to morph a series of file paths into a nested recursive structure for an Angular Material Tree component. The structure needs to be this:
interface FileTreeNode {
name: string;
children?: FileTreeNode[];
}
So a list of file paths such as ['path/to/file/01.txt', 'path/to/file/02.txt', 'another/to/file/03.txt']
will transform into:
[
{name: 'path', children: [
{name: 'to', children: [
{name: 'file', children: [
{name: '01.txt'}, {name: '02.txt'}
]
}]
}]
},
{name: 'another', children: [
{name: 'to', children: [
{name: 'file', children: [
{name: '03.txt'}
]
}]
}]
}
]
I saw a great answer for this problem here, which uses the built-in Array.reduce()
method, but I'd like to accomplish this with RxJs operators.
Here is the code I'm trying to replicate:
var paths = ["path/to/file1.doc", "path/to/file2.doc", "foo/bar.doc"],
result = [];
paths.reduce((r, path) => {
path.split('/').reduce((o, name) => {
var temp = (o.children = o.children || []).find(q => q.name === name);
if (!temp) o.children.push(temp = { name });
return temp;
}, r);
return r;
}, { children: result });
console.log(result);
Here's what I have so far:
reduce((acc, curr) => {
return curr.split('/').reduce((obj, name) => {
let temp = (obj.children != null ? obj.children : obj.children = []).find(node => node.name === name);
if (temp == null) {
obj.children.push(temp = {name});
}
return temp;
}, acc);
}, {children: []} as FileTreeNode),
But this is only returning the last node in the observable (eg. {name: 03.txt}
). What I want to be passing along is the final value of acc
as the above code does. I also would like to accomplish this using just the RxJs operators, instead of having to rely on the internal Js Array.reduce()
function if possible.
Thanks!
Upvotes: 1
Views: 466
Reputation: 15083
Use reduce exactly the same way, The difference is that you need to convert the array to a stream. You can use from
operator
paths = ["path/to/file1.doc", "path/to/file2.doc", "foo/bar.doc"];
paths$ = from(this.paths).pipe(
reduce(
(r, path) => {
path.split("/").reduce((o, name) => {
var temp = (o.children = o.children || []).find(q => q.name === name);
if (!temp) o.children.push((temp = { name }));
return temp;
}, r);
return r;
},
{ children: [] }
)
);
See this demo
Upvotes: 1