Skip to content

Instantly share code, notes, and snippets.

@kraftdorian
Created June 28, 2022 12:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kraftdorian/7a5cdba23d19c06591d17a1d6ea79581 to your computer and use it in GitHub Desktop.
Save kraftdorian/7a5cdba23d19c06591d17a1d6ea79581 to your computer and use it in GitHub Desktop.
Algorithm to map the input tree so it receives depth and position information, as well as the flat version of its nodes
interface ITreeNode<Data=unknown> {
id: string|null;
data: Data;
children: ITreeNode<Data>[];
}
interface IPositionedTreeNode<Data=unknown> extends ITreeNode<Data> {
depth: number;
parentId: ITreeNode<Data>['id'];
}
interface IPositionedTreeOutput<Data=unknown> {
tree: IPositionedTreeNode<Data>;
nodes: Record<
string,
IPositionedTreeNode<Data>
>;
}
interface ISplitReducerValue<Data=unknown> {
childTrees: IPositionedTreeOutput<Data>['tree'][];
nodes: IPositionedTreeOutput<Data>['nodes'];
}
const tree: ITreeNode<string> = {
id: '1',
data: 'A',
children: [
{
id: '2',
data: 'A->B',
children: []
},
{
id: '3',
data: 'A->C',
children: [
{
id: '4',
data: 'C->D',
children: []
}
]
},
{
id: '5',
data: 'A->E',
children: [
{
id: '6',
data: 'E->F',
children: [
{
id: '8',
data: 'F->H',
children: [
{
id: '9',
data: 'H->I',
children: []
}
]
}
]
},
{
id: '7',
data: 'E->G',
children: []
}
]
}
]
};
function ArrayFunctor<Input=unknown, Output=unknown>(
mapFn: (input: Input) => Output,
input: Array<Input>
): Array<Output> {
return input.map(mapFn);
}
function positionedTreeInsert<Data=unknown>(
parentNodeId: ITreeNode<Data>['id'],
currentNode: ITreeNode<Data>,
depthAcc: number,
nodesAcc: IPositionedTreeOutput<Data>['nodes']
): IPositionedTreeOutput<Data> {
const positionedCurrentNode: IPositionedTreeNode<Data> = {
...currentNode,
depth: depthAcc,
parentId: parentNodeId
};
switch (true) {
case currentNode.children.length > 0:
const initialReducerValue: ISplitReducerValue<Data> = {
childTrees: [],
nodes: {}
};
const childInsertSplitOutput = ArrayFunctor(
childNode => positionedTreeInsert(currentNode.id, childNode, depthAcc + 1, nodesAcc),
currentNode.children
).reduce((acc, current) => ({
childTrees: [...acc.childTrees, current.tree],
nodes: {...acc.nodes, ...current.nodes}
}), initialReducerValue);
return {
tree: {
...positionedCurrentNode,
children: childInsertSplitOutput.childTrees
},
nodes: {
...nodesAcc,
...(positionedCurrentNode.id !== null
? {
[positionedCurrentNode.id]: positionedCurrentNode
}
: {}
),
...childInsertSplitOutput.nodes
}
};
default:
return {
tree: positionedCurrentNode,
nodes: {
...nodesAcc,
...(positionedCurrentNode.id !== null
? {
[positionedCurrentNode.id]: positionedCurrentNode
}
: {}
)
}
};
}
}
const positionedTreeOutput = positionedTreeInsert(null, tree, 0, {});
console.log(positionedTreeOutput);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment