-
-
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?