I have an array of objects and I want to create a view tree. But I have a problem with creating. My name Test1/Test2 and Test1/Test2/Test3 (id 147) was missed in final tree.
My snippet:
let arr = [{id: 145, name: "Test1/Test2", public: false},
{id: 146, name: "Test1/Test2/Test3", public: false},
{id: 147, name: "Test1/Test2/Test3", public: false},
{id: 148, name: "Test1/Test2/Test4", public: false}];
let result = [];
let level = { result };
arr.forEach((path) => {
path.name.split("/").reduce((r, name, i, a) => {
if (!r[name]) {
r[name] = { result: [], id: path.id };
r.result.push({ name, children: r[name].result });
}
return r[name];
}, level);
});
console.log(result)
Expected result:
[
{
name: "Test1",
children: [
{
name: "Test2",
children: [],
id: 145
},
{
name: "Test2",
children: [
{
name: "Test3",
children: [],
id: 146
},
{
name: "Test3",
children: [],
id: 147
},
{
name: "Test4",
children: [],
id: 148
},
],
},
],
},
];
If I understand well, the number of leaves in your tree should equal the number entries in the input array. So a leaf would never get any children. This is what made you give "Test1" two children, even though all paths have "Test2" as the next part: one child for a leaf, and another functioning as internal node.
By consequence, leaves don't really need a children
property, as that children
array would always remain empty.
It is clear that the last element of a path needs to be processed a bit differently. That part should always result in the creation of a new node in the tree. The other parts can reuse a (non-leaf) node, if one is available.
This leads to the following change in your code:
let arr = [
{id: 145, name: "Test1/Test2", public: false},
{id: 146, name: "Test1/Test2/Test3", public: false},
{id: 147, name: "Test1/Test2/Test3", public: false},
{id: 148, name: "Test1/Test2/Test4", public: false}
];
let result = [];
let level = { result };
arr.forEach(({name, id}) => { // destructure
let parts = name.split("/");
name = parts.pop(); // don't pass the last part through reducer
parts.reduce((r, name, i) => {
if (!r[name]) {
r[name] = { result: [] };
r.result.push({ name, children: r[name].result });
}
return r[name];
}, level).result.push({ name, id }); // add last part here
});
console.log(result);