Constructing a hierarchical tree structure using an array of objects that are initially flat

My goal is to create a hierarchical tree structure from a flat array:

The original flat array looks like this:

nodes = [
    {id: 1, pid: 0, name: "kpittu"},
    {id: 2, pid: 0, name: "news"},
    {id: 3, pid: 0, name: "menu"},
    {id: 4, pid: 3, name: "node"},
    {id: 5, pid: 4, name: "subnode"},
    {id: 6, pid: 1, name: "cace"}
];

Note: id refers to node id and pid refers to parent node id.

The desired output should look like this:

nodes = [{
    id: 1,
    name: 'kpittu',
    childs: [{
        id: 6,
        name: 'cace'
    }]
}, {
    id: 2,
    name: 'news'
}, {
    id: 3,
    name: 'menu',
    childs: [{
        id: 4,
        name: 'node',
        childs: [{
            id: 5,
            name: 'subnode'
        }]
    }]
}];

I initially attempted to use a recursive function to achieve the desired outcome, but I am open to exploring alternative solutions. Thank you for your input.

Answer №1

One approach is to utilize a hash table and consider id and pid as linked nodes within each iteration.

This solution is effective even when dealing with unsorted data.

var nodes = [{ id: 6, pid: 1, name: "cace" }, { id: 1, pid: 0, name: "kpittu" }, { id: 2, pid: 0, name: "news" }, { id: 3, pid: 0, name: "menu" }, { id: 4, pid: 3, name: "node" }, { id: 5, pid: 4, name: "subnode" }], tree = function (data, root) { var r = [], o = {}; data.forEach(function (a) { if (o[a.id] && o[a.id].children) { a.children = o[a.id] && o[a.id].children; } o[a.id] = a; if (a.pid === root) { r.push(a); } else { o[a.pid] = o[a.pid] || {}; o[a.pid].children = o[a.pid].children...
    
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

An alternative approach is to utilize the Map object, which was introduced in ES6.

let nodes = [
  { id: 1, pid: 0, name: "kpittu" },
  { id: 2, pid: 0, name: "news" },
  { id: 3, pid: 0, name: "menu" },
  { id: 4, pid: 3, name: "node" },
  { id: 5, pid: 4, name: "subnode" },
  { id: 6, pid: 1, name: "cace" }
];

function createTree(arr) {
  let arrMap = new Map(arr.map(item => [item.id, item]));
  let tree = [];

  for (let i = 0; i < arr.length; i++) {
    let item = arr[i];

    if (item.pid) {
      let parentItem = arrMap.get(item.pid);

      if (parentItem) {
        let { children } = parentItem;

        if (children) {
          parentItem.children.push(item);
        } else {
          parentItem.children = [item];
        }
      }
    } else {
      tree.push(item);
    }
  }

  return tree;
}

let treeStructure = createTree(nodes);

console.log(treeStructure);

https://codesandbox.io/s/sparkling-feather-r6j3v?fontsize=14&hidenavigation=1&theme=dark

Answer №3

Utilize Array#reduce along with a supporting object:

var nodes = [
  {id: 1, pid: 0, name: "kpittu"},
  {id: 2, pid: 0, name: "news"},
  {id: 3, pid: 0, name: "menu"},
  {id: 4, pid: 3, name: "node"},
  {id: 5, pid: 4, name: "subnode"},
  {id: 6, pid: 1, name: "cace"}
];

const helper = nodes.reduce((h, o) => (h[o.id] = Object.assign({}, o), h), Object.create(null));

const tree = nodes.reduce((t, node) => {
  const current = helper[node.id];
  
  if(current.pid === 0) { // check for parent and push to root
    t.push(current);
  } else {
    helper[node.pid].children || (helper[node.pid].children = []) // create children array for parent if not present
    helper[node.pid].children.push(current); // add current item to parent's children array
  }
  
  return t;
}, []);

console.log(tree);

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

Error 400: The onCreate Trigger function for Cloud functions is experiencing issues with HTTP requests due to errors in the request

I am encountering an issue when attempting to add a trigger for Firestore OnCreate, as the deployment fails with HTTP Error: 400 stating that the request has errors. Essentially, my goal is to write to a new document if a record is created in a different ...

I am experiencing difficulty with the button not responding when clicked, despite trying to implement JavaScript and the Actions syntax

Currently, I am in the process of automating form filling. After filling out the form, there is an update button that changes color instead of clicking when activated. This alteration indicates that the xpath is correctly identified. I have attempted two ...

Using Selenium to interact with drop-down lists using div tags instead of select tags

As a newcomer to automated testing using Selenium Web Driver, I am struggling to test drop down lists for the location type without relying on the select command. The element in question is enclosed within a div tag. I attempted sending keys but that meth ...

Ways to retrieve element values within Angular

Here is an example of an element: <li class="someClass">value1<span>value2</span></li> This list element is created using vanilla JavaScript, and a click event is bound to it as demonstrated below: const list = Array.from(documen ...

Accessing URL fragments in Next JS with context during the execution of getServerSideProps

I am trying to extract a URL fragment using getServerSideProps. The URL is structured like this: http://localhost:3000/some-folder#desiredParam=value Even though I pass the context as an argument to the getServerSideProps function, I am struggling to retr ...

Transmit a file using multipart with XMLHttpRequest

Is it possible to use XMLHttpRequest to send a multipart file to a servlet? I am currently working on a form that needs to be submitted as multipart, but I am not receiving a response after successfully uploading it. It is important that the process happe ...

Encountering issues with the phaser framework while setting up a server on xampp, faced with errors in javascript and html

Recently, I've been working on a game using Phaser and encountered some issues while trying to run the code in XAMPP. The game's base is located at htdocs/itw/test.html, with the necessary pngs and json file stored in htdocs/itw/assets/. The pngs ...

Trigger a function in AngularJS when a div is scrolled to within a specific number of pixels from the bottom of the screen

I am experimenting with the AngularJS infinite-scroll directive. Below is the code snippet: angular.module('infiniteScroll', []) .directive('infiniteScroll', [ "$window", function ($window) { return { link:funct ...

ng-init assign value to a new object

<!DOCTYPE html> <html> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> <body> <div ng-app="myApp" ng-controller="myCtrl2" ng-init="person = new Person('Al ...

Having difficulty rendering JSON data on an HTML webpage

Currently, I am working on an API App that utilizes the Foursquare API. With the help of my getRequest function, I am able to obtain results in JSON format, which are then displayed in my console.log. However, the challenge lies in parsing the data from J ...

How can we transfer a jQuery value from an input field without using a single

This task may seem challenging. How can single quotes be eliminated from a variable when passed directly to another variable? I am using jQuery variable $("#test").val() to extract the value from an input below <input type="text" ...

Mastering MongoDB update functions in JavaScript

I've encountered some difficulties while using the MongoDB API to update a document. Despite trying various methods, none of them have been successful so far. Strangely enough, inserting and deleting documents work perfectly fine. Let me explain what ...

AngularJS and TypeScript encountered an error when trying to create a module because of a service issue

I offer a service: module app { export interface IOtherService { doAnotherThing(): string; } export class OtherService implements IOtherService { doAnotherThing() { return "hello."; }; } angular.mo ...

In Cypress, I am trying to specifically choose only numerical values from a dropdown menu. However, the list contains a mix of alphanumeric and numeric values

Looking to streamline: This is my code: cy.get('[role=presentation]') cy.get('[role=row]').find('td') .get('[role=gridcell]').eq(9).click().wait(2000) cy.get('[role=listbox]').get('[role=option]& ...

A more effective strategy for avoiding the use of directives or jQuery in AngularJS

I need guidance on using Angular directives, especially when deciding between JQuery and Angular 1 directives for a particular scenario. Here is an example of my object list: [ { "id":"sdf34fsf345gdfg", "name":"samson", "phone":"9876543210", ...

Using NicEdit for uploading to your personal server

I'm having trouble uploading images using the NicEdit WYSIWYG editor on my own server. When I click on the upload image button, it redirects me to another site where I can upload the image: imgur dot com You can find a demo of this here: However, I ...

Modifying the color of a non-active tab - Material UI Tabs

Is there a way to customize the color of inactive tabs in Material UI tabs? I have noticed that they currently appear black, as shown in the screenshot here: screenshot Thank you! ...

Extracting textual information from Wikipedia through iframes?

Currently, I am working on a website project utilizing Squarespace. This site will feature multiple pages dedicated to individuals who have reached a level of notability worthy of having their own Wikipedia page. With over 150 pages planned, manually writi ...

How can I access the backend API integrated with Keycloak through Angular?

I am encountering this error I have configured a proxy Here is my service class The URL I need to access on the backend is http://localhost:8089/greet My current goal involves integrating Keycloak with the backend and making calls from the front end. W ...

Toggle JavaScript Query Display

Welcome to my HTML test website where I am testing show/hide JavaScript functionality. Upon loading the page, you may notice that everything is hidden until a button is clicked. <html> <head><title>Test</title> <scr ...