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

php executing javascript - error

I have a question regarding my PHP file code: echo '<script type="text/javascript">'; echo '<audio id="player" src="../cdh/ba1.mp3"></audio>'; echo '<a onclick="document.getElementById( ...

Sending an HTTP POST request from an Angular 2 client to a Node.js server

I am encountering a peculiar issue with sending POST requests to my Node.js server. Although my GET listeners are functioning perfectly, when attempting to send a simple request from my Angular 2 application (port 4200) to the Node.js server (port 443), I ...

Angular Service Singleton Utilized in Components

I have a structural question regarding my Angular application. I am following the widely-used core, shared, and feature modules structure, similar to the one found here. In my core module, I have a singleton notification service defined, but I use a custom ...

What is the best way to iterate through my array of objects using a forEach loop and assign a value to the property of any object that has an empty string?

Inquiry for Part 1: I am currently exploring the use of forEach loop to iterate through an array of objects. My goal is to update the property "profile_image_url" of objects that have an empty string as its value, setting it to a default link ("/media/arti ...

EaselJS: Enhancing Performance and Aesthetics with Over 200 Vector Shapes

When comparing EaselJS performance with Canvas native methods, I noticed a significant difference: 2.2 s vs 0.01 s (despite EaselJS mapping canvas native methods). I created a canvas application that draws a tree*. For animating the growth of the tree, us ...

Using Typescript to define the type for React's useState() setter function whenever

I'm working on setting up a React Context to handle parameters mode and setMode, which act as getter and setter for a React state. This is necessary in order to update the CSS mode (light / dark) from child components. I'm encountering a Typescr ...

Can you explain the significance of a single variable line in JavaScript?

While reading a book on Angular.js, I came across the following syntax: $scope.selectedOrder; // What does this syntax mean? $scope.selectOrder = function(order) { $scope.selectedOrder = order; }; I understand that selectedOrder is a property of the $s ...

Organize data by multiple criteria using List.js

Attempting to configure the list.js plugin to allow sorting based on multiple values. Specifically, the goal is to sort by category first and then alphabetically by title within each category. See a demo here: http://jsfiddle.net/8E7cH/ This functional ...

encountered an error stating module '@angular/compiler-cli/ngc' could not be located while attempting to execute ng serve

Here is the content of my package.json file: { "name": "cal-euc", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build&qu ...

Explore how to set up Express with React without resorting to using create-react

I am familiar with the react and Node.js Express bundle, but I require assistance. While this question may have been posed by someone else before, I have not come across a similar query within the same framework. The specific question is: How can queries ...

Issue with displaying data using a custom pure pipe and boolean in ngIf condition

For my current web project, I require a friendship/follow feature. There are two roles involved: admins and regular users. Regular users have the ability to follow other users, while admins do not possess this capability. When a user wishes to follow anot ...

Refresh the block's content seamlessly without the need for a page reload

Within the index.html page There exists a block called content that contains various content blocks. An additional navigation menu with numerous links is present. It is important that when you click on a menu link, the content within the content block re ...

The random quote generator or current tweet quote feature is malfunctioning

I am having trouble with a jQuery on click function that is not working to tweet the current quote. I am working on building a random quote machine and tweeting the current quote is essential. Despite successfully implementing the JSON API, I cannot seem t ...

Should we bundle everything into one script with webpack, considering Npm and Dev dependency or just dependencies?

Imagine a scenario where we use webpack to bundle all our code into a single JS file, which automatically imports dependencies. In this case, is it necessary to include any dependencies in the package.json, or can they all be listed as --save-dev? Let&apo ...

Ways to eliminate the lower boundary of Input text

Currently, I am working on a project using Angular2 with Materialize. I have customized the style for the text input, but I am facing an issue where I can't remove the bottom line when the user selects the input field. You can view the red line in t ...

Concatenating an unlimited amount of arrays containing Javascript objects

I currently have an array of Groups where each Group contains multiple Users. My goal is to retrieve all the unique Users associated with a given array of Groups. Here is my current approach: let actor = await User.query().findById(req.user.id).eager( ...

What is the best way to distinguish the compiled files from the source code, while still being able to test and view Express views directly from the source?

I am embarking on a new project using node. I have chosen to organize my directory structure by keeping all source files under ./src and the files intended for server upload under ./dist. The semi-complete directory layout is displayed below. Once built, t ...

How can we ensure that an enum is accessible throughout the entire meanjs stack?

Currently, I am exploring the meanjs technology stack and facing a challenge in creating a centralized enum array that can be accessed throughout the project, from MongoDB to Angular. Can anyone suggest a smart solution for accomplishing this task? ...

The function cannot be called because the type does not have the appropriate signature for invoking. The specific type lacks compatible call signatures, as indicated

Encountering an issue while attempting to utilize a getter and setter in my service, resulting in the following error message: Cannot invoke an expression whose type lacks a call signature. Type 'Boolean' has no compatible call signatures 2349 t ...

What is the best way to send parameters to an angular service or factory?

This Plunker demonstration is a great visual guide: http://plnkr.co/edit/y3uacaQSc1MbrWKfb0At?p=preview Here's the code snippet for reference: var app = angular.module('plunker', []); app.controller('MainCtrl', function($scope,t ...