Reputation: 486
I'm trying build a tree from a flat list, and I know I'm missing something that would make this much easier and faster. I've tried several approaches. The latest being the function I've posted below.
The flat list that looks like this:
var input = [
{
"Parent Category": "Agricultural Feed + Seed",
Category: "Agricultural Feed + Seed",
Name: "Agfinity"
},
{
"Parent Category": "Agricultural Feed + Seed",
Category: "Agricultural Feed + Seed",
Name: "Agland Co-op"
},
{
"Parent Category": "Agricultural Feed + Seed",
Category: "Agricultural Equipment",
Name: "Agri Supply"
},
{
"Parent Category": "Agricultural Equipment",
Category: "Tractors",
Name: "Agway"
},
{
"Parent Category": "Agricultural Equipment",
Category: "Tractors",
Name: "Agway2"
},
{
"Parent Category": "Travel",
Category: "Travel",
Name: "Amtrak"
},
{
"Parent Category": "Travel",
Category: "Accessories",
Name: "Bentley Leathers & Luggage"
}
];
From this list I'm trying to build a tree that looks like this:
[
{
"label": "Agricultural Feed + Seed",
"children": [
{
"label": "Agfinfity"
},
{
"label": "Agland Co-op"
},
{
"label": "Agricultural Equipment",
"children": [
{
"label": "Agri Supply"
"children": [
{
"label": "Tractors",
"children": [
{
"label": "Agway"
},
{
"label": "Agway2"
}
]
}
]
}
]
}
]
},
{
"label": "Travel",
"children": [
{
"label": "Amtrak"
},
{
"label": "Acessories",
"children": [
{
"label": "Bentley Leathers & Luggage"
},
}
]
}
];
I have a function like this that almost works, but I know it's not the right approach.
function formatBrandNames(rawBrands) {
let output = [];
for (let i = 0; i < rawBrands.length; i++) {
// Parent Category
if (!output.find(v => v.label === rawBrands[i]["Parent Category"])) {
output.push({
label: rawBrands[i]["Parent Category"],
children: []
});
}
// Category
let parentCat = output.find(v => v.label === rawBrands[i]["Parent Category"]);
if (rawBrands[i]["Category"] === parentCat.label) {
const name = trimBrandNumbers(rawBrands[i]["Name"]);
parentCat.children.push({ label: name });
continue;
}
if (!parentCat.children.find(v => v.label === rawBrands[i]["Category"])) {
parentCat.children.push({ label: rawBrands[i]["Category"], children: [] });
}
// Name
let cat = parentCat.children.find(v => v.label === rawBrands[i]["Category"]);
const name = trimBrandNumbers(rawBrands[i]["Name"]);
cat.children.push({ label: name });
}
return output;
}
Any help or insight on this would be greatly appreciated.
Upvotes: 0
Views: 248
Reputation: 138267
The logic can be simplified to
If the node has no parent category, it is one of the root categories
Find the Parent by it's category, then add the node to the parent's children
If the parent does not exist, create it.
function toTree(nodes) {
const roots = [];
const byCategory = new Map();
for(const { Name: label, ["Parent Category"]: parent, Category: category } of nodes) {
const node = { label, children: [] };
if(byCategory.has(category)) {
byCategory.get(category).children.push(node);
} else {
const categoryObj = {
label: category,
children: [node]
};
byCategory.set(category, categoryObj);
if(parent === category) {
roots.push(categoryObj);
} else if(byCategory.has(parent)) {
byCategory.get(parent).children.push(categoryObj);
} else {
byCategory.set(parent, { label: parent, children: [categoryObj] });
}
}
}
return roots;
}
Upvotes: 1