Steps to generate an unlimited tree structure using a specified set of data organized by parent ID

I have a collection structured like this:

interface Elm {
  id: number;
  name: string;
  parent?: number;
}

Now, I would like to transform it into the following format:

interface NodeTree {
  id: number;
  name: string;
  children: NodeTree[];
  parent?: number;
}

To achieve this, I need a function that can iterate through an array of elements and organize them into a tree structure.

Here is an example of the given elements:

const elements: Elm[] = [   { id: 1, name: "Hydrogen" },   { id: 2, name: "Helium" },   { id: 3, name: "Lithium" },   ...

How can I generate the output in the form of NodeTree[]?

Answer №1

interface Element {
  identifier: number;
  title: string;
  parentID?: number;
}

interface TreeView {
  id: number;
  name: string;
  childNodes: TreeView[];
  parentID?: number;
}

const elementsList: Element[] = [
  { identifier: 1, title: "Hydrogen" },
  { identifier: 2, title: "Helium" },
  { identifier: 3, title: "Lithium" },
  { identifier: 4, title: "Beryllium" },
  // Add more elements
];

const treeNodes: TreeView[] = [];

const createTreeNode = (element: Element) => {
  const treeNode: TreeView = {
    id: element.identifier,
    name: element.title,
    childNodes: [],
    parentID: element.parentID
  };
  return treeNode;
};

const fillElementsInNode = (elements: Element[], treeNode: TreeView) => {
  elements.forEach(element => {
    if (element.parentID === treeNode.id) {
      const childNode = treeNode.childNodes.find(
        (child: TreeView) => child.id === element.identifier
      );

      if (!childNode) {
        treeNode.childNodes.push(createTreeNode(element));
      }
    }
  });
};

const fillTreeView = (elements: Element[], treeNode: TreeView) => {
  fillElementsInNode(elements, treeNode);

  if (treeNode.childNodes.length > 0) {
    treeNode.childNodes.forEach(node => {
      fillElementsInNode(elements, node);
      fillTreeView(elements, node);
    });
  }
};

elementsList.forEach(element => {
  if (!element.parentID) {
    const rootTreeNode: TreeView = createTreeNode(element);
    fillTreeView(elementsList, rootTreeNode);
    treeNodes.push(rootTreeNode);
  }
});

console.table(treeNodes);
console.log("🚩");
console.table(treeNodes[0].childNodes);
console.log("🚩");
console.table(treeNodes[0].childNodes[0].childNodes);
console.log("🚩");
console.table(treeNodes[0].childNodes[0].childNodes[0].childNodes);

Answer №2

To begin, it's best to start at the bottom of the tree and work your way up to the top. Various algorithms can help in extracting all the leaf nodes from a tree structure

Add the current element as a child to its parent node.

Once you've finished with the leaves, move up one level and repeat the process until you reach the root.

Answer №3

const elementsArray = [
  { id: 1, name: "Hydrogen" },
  { id: 2, name: "Helium" },
  { id: 3, name: "Lithium" },
  { id: 4, name: "Beryllium" },
  { id: 5, name: "Boron" },
  { id: 6, name: "Carbon" },
  { id: 7, name: "Nitrogen" },
  { id: 8, name: "Oxygen" },
  { id: 9, name: "Fluorine" },
  { id: 10, name: "Neon" },
  ...
];
const nodeList = [];
const createNodeElement = (element) => {
  const nodeElement = {
    id: element.id,
    name: element.name,
    children: [],
    parent: element.parent
  };
  return nodeElement;
};
const fillElementsArray = (elementsArray, rootNode) => {
  elementsArray.forEach((element) => {
    if (element.parent === rootNode.id) {
      const childNode = rootNode.children.find((child) => child.id === element.id);
      if (!childNode) {
        rootNode.children.push(createNodeElement(element));
      }
    }
  });
};
const fillTreeStructure = (elementsArray, rootNode) => {
  fillElementsArray(elementsArray, rootNode);
  if (rootNode.children.length > 0) {
    rootNode.children.forEach((node) => {
      fillElementsArray(elementsArray, node);
      fillTreeStructure(elementsArray, node);
    });
  }
};
elementsArray.forEach((element) => {
  if (!element.parent) {
    const rootElement = createNodeElement(element);
    fillTreeStructure(elementsArray, rootElement);
    nodeList.push(rootElement);
  }
});
console.table(nodeList);
console.log("🚩");
console.table(nodeList[0].children);
console.log("🚩");
console.table(nodeList[0].children[0].children);
console.log("🚩");
console.table(nodeList[0].children[0].children[0].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

Tips for creating a custom Angular Material modal window that is fully responsive to its parent modal window

Hey there! I've put together a custom modal window in Angular Material by combining the custom modal window example with the Angular Material slider demo. Everything is working well except for the fact that the sliders inside the modal window are not ...

Complete my search input by utilizing ajax

It's only been 30 minutes since my last post, but I feel like I'm making progress with my search posts input: I've developed a model that resembles this: function matchPosts($keyword) { $this->db->get('posts'); ...

Textarea is limited to resizing just one specific area

I've been experiencing issues with my textareas. The problem arises when I try to have multiple textareas that need to resize on page load. It seems to work well for the first textarea, but as soon as I insert another one, only the first one responds ...

Is it considered poor practice in TypeScript to manually set the type when the type inference is already accurate?

Is it necessary to explicitly set the variable type in TypeScript when it is inferred correctly? For example: const add = (a: number, b: number) => a + b; const result = add(2, 3); // Or should I explicitly declare the return value type? const add = ...

Updating a React JS State using a Parameter

Is it feasible to develop a function that accepts a parameter (either a string of the state name or the actual state) and then assigns the state related to the parameter? SetState(x) { // Suppose x can be any state we have already defined (it sh ...

Center align your animations without using the text-align property

I'm in the process of refining this custom animation to make it smoother. Check out the live animation here. The issue I'm encountering is that during the transition when the city name rotates up and replaces the old one, the text-align center ...

Trouble setting custom attribute tags in Ionic 4

Trying to apply custom attributes within a ngFor loop is proving challenging for me. <ng-container *ngFor="let a of this.current_items?.areas; let i = index"> ... I've made several attempts: <div class="productBatchArea" custom-data=&apo ...

A comparison between the if statement and switch statement in JavaScript

Let's dive into a challenging scenario for those who consider themselves experts in JavaScript, particularly with switch and if statements. Here is how it typically works: var a = 1; if (a == 1) alert("true"); This is just a basic example. Now, let& ...

Obtain a URL using JavaScript's regular expressions

Is it possible to use JavaScript regex to fetch the first function parameter? For instance, when I click on a tag in this page element, how can I extract the inline link? Here's an example: <li><a href="#blog" data-rel="clos ...

Once I introduce ngModel into mat-checkbox, the functionality of 'checked' stops working

When I add an ngModel to my mat-checkbox, the checked = "checked" functionality stops working as expected. The following code will work: <mat-checkbox name="BlackBeard" ngModel checked = "checked"> Zehahaha? </mat-checkbox> However, the foll ...

Error: React-Redux unable to locate Redux context value while utilizing useSelector function

After creating a store and authreducer, everything was working as expected. However, when I added the useSelector in app.js, an error occurred: ERROR Error: could not find react-redux context value; please ensure the component is wrapped in a <Provid ...

Properly citing JQuery references

Attempting to incorporate Jquery for the first time, I've encountered an issue. Specifically, I am utilizing VS 2013, asp.net, and VB. Within my head tag, the structure is as shown below. <head runat="server"> <title></title> ...

What methods can be used to block the input of non-numeric characters in a text field?

I stumbled upon this particular inquiry. Although, the majority of responses involve intercepting key presses, checking the key code, and halting the event if it does not match an acceptable key code. However, there are some issues with this approach. ...

Automatically relaunch NodeJS application upon app failure

I am looking for a way to automatically restart my NodeJS (Express) app after crashes with errors. I am familiar with the forever npm package, but all the examples I found were for running the app in development. My goal is to implement this in production ...

What are the steps to generating and sharing 'npm create' scripts?

I am looking to develop and release a script on npm that functions similarly to: npm create qwik@latest or yarn create next-app --typescript However, I am unsure where to begin. Despite searching extensively online, I have not been able to find any helpf ...

Mobile site experiencing slow scrolling speed

The scrolling speed on the mobile version of my website, robertcable.me, seems to be sluggish. Despite conducting thorough research, I have not been able to find a solution. I have attempted to address the issue by removing background-size: cover from my ...

Simplified JavaScript code for generating concealed input forms

Seeking assistance to enhance the form I designed, despite my limited knowledge in JavaScript programming. The objective is to develop a hotel search engine with the ability to specify the total number of rooms. Based on the selected number of rooms, addi ...

What is the process for converting an <input type="file> into a base64 string?

Currently, I'm attempting to send an image to my express backend by including the image directly in the post request body. var imgValue = document.getElementById("image").value; Within my post request: body : JSON.stringify({ image:imgValue ...

Exploring the process of sending post data and navigating to a URL using AngularJS

I am working on an application using angularjs 1.6 and Java 8. My goal is to send POST data to another application and navigate to the URL that this external application determines. The purpose of my application is to transmit data about a citizen who wan ...

Service B is receiving query parameters from Service A in a peculiar object format, leaving us puzzled as to the reason behind this unexpected structure

Issue: Encountered a strange bug when our service A (using laravel php) makes a call to an endpoint in service B (built with nodejs typescript + ajv + nestjs). Further explanation of the issue below. Below is an example of code in service A for constructi ...