Skip to content

Instantly share code, notes, and snippets.

@GautamPanickar
Last active January 28, 2021 18:15
Show Gist options
  • Save GautamPanickar/f84cc7a5c97a390b237a6a26943efdb4 to your computer and use it in GitHub Desktop.
Save GautamPanickar/f84cc7a5c97a390b237a6a26943efdb4 to your computer and use it in GitHub Desktop.
export interface IAccount {
id: number;
name: string;
pid: number;
code: string;
desc?: string;
}
export interface AccountNode {
level?: number;
account: IAccount;
children?: AccountNode[];
}
class TreeHelper {
public static formatTree(data: IAccount[]): AccountNode[] {
let accountTree: AccountNode[] = [];
let rootAccountIds: number[] = [];
let leafAccounts: IAccount[] = [];
let parentInfo: { level: number, id: number }[] = [];
let i = 0;
while (i < data.length) {
const account = data[i];
if (TreeHelper.isRootAccount(account)) {
accountTree.push({ account: account, children: [] });
rootAccountIds.push(account.id);
} else {
leafAccounts.push(account);
}
i++;
}
leafAccounts.forEach(l => {
if (rootAccountIds.indexOf(l.pid) >= 0) {
parentInfo.push({
level: 0,
id: l.pid
});
}
});
let orderedNodes: AccountNode[] = [];
let level = 0;
while (leafAccounts.length > 0) {
let i = 0;
while (i < leafAccounts.length) {
const account = leafAccounts[i];
const parentIndex = parentInfo.findIndex(p => p.level === level && p.id === account.pid);
if (parentIndex >= 0) {
// Now that leaf is handld remove it
leafAccounts.splice(i, 1);
// Find and insert the node at the correct position.
let nodeToInsert = TreeHelper.findAccountNodeToInsert(account.pid, orderedNodes);
if (nodeToInsert) {
nodeToInsert.children.push({ account: account, children: [] });
} else {
nodeToInsert = { account: account, children: [] };
orderedNodes.push(nodeToInsert);
}
// Corresponding parent of the leaf is also handled, which makes it removable too
parentInfo.splice(parentIndex, 1);
// Push the current leaf's id as the new parent and increase the depth of the level
parentInfo.push({
level: level + 1,
id: account.id
});
} else {
i++;
}
}
level++;
}
// Attach the ordered nodes to the root nodes.
i = 0;
while (i < orderedNodes.length) {
const account = orderedNodes[i].account;
const rootNode = accountTree.find(n => n.account.id === account.pid);
rootNode.children.push(orderedNodes[i]);
i++;
}
return accountTree;
}
public static isRootAccount(account: IAccount): boolean {
return !account.pid || account.pid <= 0;
}
private static findAccountNodeToInsert(id: number, nodes: AccountNode[]): AccountNode {
let foundNode: AccountNode;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (node.account.id === id) {
foundNode = node;
break;
} else if (node.children.length > 0) {
foundNode = TreeHelper.findAccountNodeToInsert(id, node.children);
if (foundNode) {
break;
}
}
}
return foundNode;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment