-
-
Save stephanbogner/4b590f992ead470658a5ebf09167b03d to your computer and use it in GitHub Desktop.
var paths = [ | |
["Account"], | |
["Account", "Payment Methods"], | |
["Account", "Payment Methods", "Credit Card"], | |
["Account", "Payment Methods", "Paypal"], | |
["Account", "Emails"], | |
["Account", "Emails", "Main Email"], | |
["Account", "Emails", "Backup Email"], | |
["Account", "Devices"], | |
["Account", "Devices", "Google Pixel"], | |
["Account", "Devices", "iPad Mini"], | |
["Account", "Devices", "Laptop"] | |
]; | |
var tree = arrangeIntoTree(paths); | |
console.log(JSON.stringify(tree, null, 4)); | |
// Result | |
// [ | |
// { | |
// "name": "Account", | |
// "children": [ | |
// { | |
// "name": "Payment Methods", | |
// "children": [ | |
// { | |
// "name": "Credit Card", | |
// "children": [] | |
// }, | |
// { | |
// "name": "Paypal", | |
// "children": [] | |
// } | |
// ] | |
// }, | |
// { | |
// "name": "Emails", | |
// "children": [ | |
// { | |
// "name": "Main Email", | |
// "children": [] | |
// }, | |
// { | |
// "name": "Backup Email", | |
// "children": [] | |
// } | |
// ] | |
// }, | |
// { | |
// "name": "Devices", | |
// "children": [ | |
// { | |
// "name": "Google Pixel", | |
// "children": [] | |
// }, | |
// { | |
// "name": "iPad Mini", | |
// "children": [] | |
// }, | |
// { | |
// "name": "Laptop", | |
// "children": [] | |
// } | |
// ] | |
// } | |
// ] | |
// } | |
// ] | |
function arrangeIntoTree(paths) { | |
// Adapted from http://brandonclapp.com/arranging-an-array-of-flat-paths-into-a-json-tree-like-structure/ | |
var tree = []; | |
for (var i = 0; i < paths.length; i++) { | |
var path = paths[i]; | |
var currentLevel = tree; | |
for (var j = 0; j < path.length; j++) { | |
var part = path[j]; | |
var existingPath = findWhere(currentLevel, 'name', part); | |
if (existingPath) { | |
currentLevel = existingPath.children; | |
} else { | |
var newPart = { | |
name: part, | |
children: [], | |
} | |
currentLevel.push(newPart); | |
currentLevel = newPart.children; | |
} | |
} | |
} | |
return tree; | |
function findWhere(array, key, value) { | |
// Adapted from https://stackoverflow.com/questions/32932994/findwhere-from-underscorejs-to-jquery | |
t = 0; // t is used as a counter | |
while (t < array.length && array[t][key] !== value) { t++; }; // find the index where the id is the as the aValue | |
if (t < array.length) { | |
return array[t] | |
} else { | |
return false; | |
} | |
} | |
} |
Hey, it's pure gold - exactly what I was Looking for. I am using it to build tree structure based on array of URL's. Of course, firstly I've split every url into an array of paths. Then to achieve fullUrl of current path I had to change one thing, link so:
var newPart = { fullUrl: path .slice(0, j + 1) .join("/") .replace("http/", "http://") .replace("https/", "https://"), name: part, children: [], };
Just what I need Thanks
Thanks.
Thanks , it works for me .
Thanks a lot man saved my day
Thank u bro <3
still perfect work 👍
might be missing something but does line 90 need to be there? seems to be working without it?
might be missing something but does line 90 need to be there? seems to be working without it?
Honestly ... I don't know ... it's been so many years since I wrote the code ^^
might be missing something but does line 90 need to be there? seems to be working without it?
Honestly ... I don't know ... it's been so many years since I wrote the code ^^
haha yes 5 years, very fair - this was helpful non the less thank you!
Thanks! I ended up writing a more modern typescript version of it.
Its input-output is a bit different as it works with data objects instead of plain paths.
This allows to have data attached / retained to every path node.
export interface TreeNode<TData=any> {
name:string,
children?:TreeNode[],
data?:TData,
}
export function arrangeObjectsIntoTree<TData extends Record<string,any>>(objects:TData[], pathProperty:string):TreeNode<TData>[] {
const tree = [];
for (let i = 0; i < objects.length; i++) {
const obj = objects[i];
let path:string[];
if(Array.isArray(obj[pathProperty])) path = obj[pathProperty] ;
else if (typeof obj[pathProperty] === 'string') path = obj[pathProperty].split('/');
else throw new Error('Could not parse path property')
let currentParentNodeList:TreeNode<TData>[] = tree;
for (let j = 0; j < path.length; j++) {
const pathSegment = path[j];
const isFinalSegment = j+1 === path.length;
const existingNode = currentParentNodeList.find(node=>node.name === pathSegment)
if (existingNode) {
currentParentNodeList = existingNode.children;
} else if(isFinalSegment) {
currentParentNodeList.push({
name: pathSegment,
data: obj,
});
} else {
currentParentNodeList.push({
name: pathSegment,
children: [],
});
currentParentNodeList = currentParentNodeList[currentParentNodeList.length-1].children;
}
}
}
return tree;
}
Usage example:
arrangeObjectsIntoTree([
{ foo:'bar', path:'my/tree/dir' },
{ foo:'bar', path:['my','other','dir'] },
], 'path'
Just like the original script, it will create a nested structure of objects containing name and children properties.
Additionally, each "entry" node will contain a data property which stores the original object.
Just what I needed 👍 Thanks!