dashersupply/src/types/tree.ts

175 lines
5.6 KiB
TypeScript

/**
* A simple tree data structure.
*/
export class TreeNode<NodeT> {
private _value: NodeT;
private _children: TreeNode<NodeT>[];
private _parent?: TreeNode<NodeT>;
constructor(value: NodeT) {
this._value = value;
this._children = [];
this._parent = undefined;
}
/**
* Creates a TreeNode root node.
* @param value Root node value.
* @returns TreeNode root node.
*/
public static createRoot<NodeT>(value: NodeT): TreeNode<NodeT> {
return new TreeNode(value);
}
/**
* Adds value node to parent TreeNode and returns child TreeNode.
* @param value Child node value.
* @returns Child tree node.
*/
public addChild(value: NodeT): TreeNode<NodeT> {
let childTreeNode = new TreeNode(value);
childTreeNode._parent = this;
let length = this._children.push(childTreeNode);
return this._children[length-1];
}
/**
* Gets value of node.
*/
public get value(): NodeT {
return this._value;
}
/**
* Sets value of node.
*/
public set value(value: NodeT) {
this._value = value;
}
/**
* Gets TreeNode parent of current TreeNode.
* @returns Parent TreeNode of current TreeNode.
*/
public parent(): TreeNode<NodeT> {
return this._parent||this;
}
/**
* Gets root TreeNode node of tree.
* @returns Root TreeNode node of tree.
*/
public root(): TreeNode<NodeT> {
if (this.parent() === this) {
return this;
}
else {
return this.parent().root();
}
}
/**
* Sets new parent of node and returns this TreeNode node.
* @param parent Parent of node.
* @returns This TreeNode node.
*/
public setParent(parent: TreeNode<NodeT>) {
this._parent = parent;
return this;
}
/**
* Gets children of this TreeNode node as an Array of node values.
*/
public get children(): TreeNode<NodeT>[] {
return this._children;
}
/**
* Checks to see if the current node value matches the predicate.
* @param predicate Predicate determines truthiness of the match.
* @returns Boolean indicating if this tree node value matches the predicate.
*/
public is(predicate: (value: NodeT) => boolean): boolean {
const result = predicate(this.value);
return result;
}
/**
* Performs shallow search for the predicate among itself and its TreeNode children, checking the values against the predicate.
* @param predicate Predicate determines truthiness of the match.
* @returns The TreeNode matching the predicate, if it exists. Otherwise, undefined.
*/
public findOne(predicate: (value: NodeT) => boolean): TreeNode<NodeT> | undefined {
const initialIs = this.is(predicate);
if (initialIs) {
return this;
}
else {
for (const child of this.children) {
const result = child.is(predicate);
if (result) {
return child;
}
}
}
}
/**
* Performs shallow search for the predicates among itself and its TreeNode children, checking the values against the predicate.
* @param predicate Predicate determines truthiness of the matches.
* @returns An array of TreeNodes matching the predicate, or an empty array if no predicates exist.
*/
public findAll(predicate: (value: NodeT) => boolean): TreeNode<NodeT>[] {
let results: TreeNode<NodeT>[] = [];
if (this.is(predicate)) {
results.push(this);
}
for (const child of this.children) {
if (child.is(predicate)) {
results.push(child);
}
}
return results;
}
/**
* Performs deep search for value among itself and its TreeNode children, checking the values against the predicate.
* @param predicate Predicate determines truthiness of the match.
* @returns The TreeNode matching the predicate, if it exists. Otherwise, undefined.
*/
public findOneRecursive(predicate: (value: NodeT) => boolean): TreeNode<NodeT> | undefined {
const initialFindOne = this.findOne(predicate);
if (initialFindOne) {
return initialFindOne;
}
if (this.children.length) {
for (let child of this.children) {
let result = child.findOneRecursive(predicate);
if (result) {
return result;
}
}
}
return undefined;
}
/**
* Performs deep search for value among TreeNode children, checking the values against the predicate.
* @param predicate Predicate determines truthiness of the matches.
* @returns The TreeNode matching the predicate, if it exists. Otherwise, undefined.
*/
public findAllRecursive(predicate: (value: NodeT) => boolean): TreeNode<NodeT>[] {
let results: TreeNode<NodeT>[] = [];
if (this.is(predicate)) {
results.push(this);
}
if (this.children.length) {
for (let child of this.children) {
let childResults = child.findAllRecursive(predicate);
if (childResults.length) {
results.push(...childResults);
}
}
}
return results;
}
/**
* Flattens the tree into an array of TreeNodes.
*/
public getAllNodes(): TreeNode<NodeT>[] {
let nodes: TreeNode<NodeT>[] = [];
nodes.push(this);
for (let child of this.children) {
nodes.push(...child.getAllNodes());
}
return nodes;
}
}