Creating hierarchical TreeNode structure in TypeScript

As I work with a flat one-dimensional array of type TreeNode (view interface definition below), my goal is to recursively traverse the array and add subsequent array elements as children.

While attempting a non-recursive approach using a buffer, I encountered an issue when trying to handle

node.children[0].children[0]...children[0]
since each parent has only one child.

    Childify(results: TreeNode[]): any {
    var node: TreeNode;
    var buffer: TreeNode;
    var count: number = 0;

    for (var res of results) {
        if (count == 0) {
            node = res[0];
            buffer = res[0];
            buffer.children = [];
            node.children = [];
        } else if (count == 1) {
            buffer.children = res[0];
        } else {
            node = buffer;
            node.children = [];
            node.children.push(res[0]);
            buffer = <TreeNode>node.children;
        }

        count++;
    }
}

Interface definition:

export interface TreeNode {
label?: string;
data?: any;
icon?: any;
expandedIcon?: any;
collapsedIcon?: any;
children?: TreeNode[];  <---------------
leaf?: boolean;
expanded?: boolean;
type?: string;
parent?: TreeNode;
partialSelected?: boolean;
styleClass?: string;
draggable?: boolean;
droppable?: boolean;
selectable?: boolean;

}

The input:

TreeNode[] = [treeNode1, treeNode2, treeNode3, treeNode4,...,treeNodeX]

The output will be a nested TreeNode object, structured by the children property (which is also of TreeNode type):

TreeNode = treeNode1
treeNode1.children = treeNode2
treeNode2.children = treeNode3
treeNode3.children = treeNode4
treeNodeX-1.children = treeNodeX

I am seeking a method to dynamically access treeNode1.children[0].children[0]......children[0] in a loop for X number of children to assign to the next level of children in treeNode1.

Answer №1

While I may not have experience with TypeScript, I can offer a solution using JavaScript:

const elements = [ new Element("element1"),
                   new Element("element2"),
                   new Element("element3"),
                   new Element("element4"),
                   new Element("element5")
                 ];

const result = elements.reduceRight((child, parent) => {
    parent.children.push(child);
    return parent;
});

console.log(result);

function Element(name) {
    this.name = name;
    this.children = [];
}

I hope this approach proves helpful for your needs.

Answer №2

I have created a customized algorithm just for you using simple javascript, which can easily be adapted to match your typescript interface.

Below is the code snippet for the algorithm:

var flatNodes = [
    {
        name: 'node1',
        children: []
    },
    {
        name: 'node2',
        children: []
    },
    {
        name: 'node3',
        children: []
    },
    {
        name: 'node4',
        children: []
    },
    {
        name: 'node5',
        children: []
    }
];

function linkNodes(flatNodes) {
    flatNodes = flatNodes.slice(); //creating a copy of the list

    flatNodes = flatNodes.reverse();

    for (var i = 1; i < flatNodes.length; i++) {
        var previousNode = flatNodes[i - 1];
        var currentNode = flatNodes[i];

        currentNode.children.push(previousNode);
    }

    return flatNodes[flatNodes.length - 1];
}

console.log(linkNodes(flatNodes));

You can see the output of the algorithm below:

{
    "name": "node1",
    "children": [
        {
            "name": "node2",
            "children": [
                {
                    "name": "node3",
                    "children": [
                        {
                            "name": "node4",
                            "children": [
                                {
                                    "name": "node5",
                                    "children": []
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React Router is used to render routes that do not match the specified path

I am utilizing TypeScript in React Router. I have defined two routes: / and /pages/id. class MyComponent extends React.Component { render() { return <BrowserRouter> <div> <Route exact path='/' ch ...

What is the best way to arrange an array in either javascript or typescript based on a specific key, and in the case of identical keys,

Below is an array with objects that need to be sorted: [ { "Books": [], "_id": "5dea9a11a8e1bf301c462ce4", "FileName": "AAAAA", "Order": 99999 }, { "_id": "5dea9864a8e1bf301c462cdb", "Books": [], "FileName": "some1", ...

Depend on a mapping function to assign a value to every option within a discriminated union

While utilizing all variations of a discriminated union with conditional if statements in TypeScript, the type is narrowed down to the specific variant. To achieve the same effect by expressing the logic through a mapping from the discriminant to a funct ...

Do not include ChangeDetectionStrategy when creating component

Is it possible to eliminate the default ChangeDetectionStrategy for each component creation? (Please note that I am working with Angular V 10 in a controlled environment for project maintenance) @Component({ xyz, changeDetection: ChangeDetectionStrategy. ...

Ways to identify modifications from a BehaviorSubject and automatically trigger a response according to the updated value

I am currently implementing a BehaviorSubject for managing languages in my Angular project. I am also utilizing Angular Datatables and trying to dynamically change the language displayed in the data table based on the value returned from the subscription. ...

Typescript fill() function like Laravel's fill()

One interesting feature in Laravel is the fill() method of every database model, which only assigns fields marked as "mass assignable" to the class property. (https://laravel.com/docs/5.8/eloquent#mass-assignment) public class Rectangle { protected $f ...

Retrieving data from a dynamic array using jQuery

Within my code, I am working with an array that contains IDs of div elements (specifically, the IDs of all child div elements within a parent div with the ID of #area): jQuery.fn.getIdArray = function () { var ret = []; $('[id]', this).each(fu ...

Could someone provide a detailed explanation of exhaustMap in the context of Angular using rxjs?

import { HttpHandler, HttpInterceptor, HttpParams, HttpRequest, } from '@angular/common/http'; import { Injectable } from '@core/services/auth.service'; import { exhaustMap, take } from 'rxjs/operators'; import { Authe ...

Firestore rule rejecting a request that was meant to be approved

Recently, I came across some TypeScript React code that fetches a firestore collection using react-firebase-hooks. Here's the snippet: const [membersSnapshot, loading, error] = useCollectionData( query( collection(db, USERS_COLLECTION).withConve ...

Tips for creating a seamless merge from background color to a pristine white hue

Seeking a seamless transition from the background color to white at the top and bottom of the box, similar to the example screenshot. Current look: The top and bottom of the box are filled with the background color until the edge https://i.stack.imgur.com ...

Transforming dynamic class based on state value from React to TypeScript

I'm trying to implement this React function in TypeScript, but I'm encountering errors. const ListItem = ({ text }) => { let [showMore, setShowMore] = useState(false); return ( <div className="item"> ...

Tips for accessing an API and setting up data mapping for a data table in nuxt.js

I desperately need assistance. I have been struggling with this issue for a while now, but all my attempts have ended in failure. My objective is to retrieve API data that corresponds to an array containing name, id, and email, and then display this inform ...

Setting up Typescript error handling for next-auth getProviders configuration

I recently started learning Typescript and came across a tutorial using next-auth. However, I encountered an error while following the tutorial with Typescript when using the getProviders function. https://i.stack.imgur.com/H5LaL.png https://i.stack.imgu ...

Is it possible for transclusion to display content from external sources using *ngIf and <ng-content>?

In my Angular4 Project, I have come across this snippet of code: <div class="divider"></div> <ng-content select=".nav-toggle"></ng-content> Now, I am trying to figure out a way to display the divider only when there is content pr ...

An unhandled promise rejection occurred because no routes could be found to match. URL Segment:

I'm facing an issue with my application where it doesn't recognize the route even though I have defined and imported it in app.module. Whenever I try to redirect to a specific route upon data retrieval, I encounter this exception: onSubmit(){ ...

Challenges arise when multiple threads attempt to manipulate a matrix

I'm facing a challenge in changing the main diagonal of a matrix using multithreading. Each thread is assigned a unique number: 21, 17, 16, 26, 7. However, I've encountered an issue where only the first thread seems to be working and updating the ...

Working with a function in the stylesheet of TypeScript in React Native allows for dynamic styling

When attempting to use variables in my StyleSheet file, I encounter a type error even though the UI works fine. Any suggestions on how to resolve this issue? type buttonStyle = (height: number, width: string, color: string) => ViewStyle; export type St ...

A comparison between Buffer.byteLength and file size

I'm facing an issue with file size discrepancies. I have a file that is reported as 51Mb in Finder, but when uploaded to the server, the byteLength of the Buffer shows a much smaller size. Could this difference be due to the file type or other propert ...

Reach out to the property via phone if it is listed in the JSON

When receiving JSON data from the server, I come across two different structures: JSON 1: { [{ name : 'sample1', code:'sample code 1', data : { display :'test' } ...

Using mergeMap in conjunction with retryWhen allows for the resumption of retries from the exact point of failure, without needing

I have a list of URLs, the number of which is unknown until it stops (depending on some condition). This is how I am currently using them: from(observableUrls) .pipe( mergeMap(url => callHttpService(url) , 4), retryWhen( // Looking f ...