-
-
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; | |
| } | |
| } | |
| } |
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.
might be missing something but does line 90 need to be there? seems to be working without it?