Each branch of the data structure is meticulously separated using recursion

I am struggling with a recursive data structure similar to the example provided below. My goal is for each branch, starting from null (parentTagId), to extend as far as the final one.

I have no clue on how to achieve this, so any suggestions would be greatly appreciated!

Original data:

[ 
  { TagId: 2, ParentTagId: null, Name: 'women' },
  { TagId: 5, ParentTagId: 2, Name: 'bottom' },
  { TagId: 4, ParentTagId: 2, Name: 'top' },
  { TagId: 7, ParentTagId: 4, Name: 'shirt' },
  { TagId: 8, ParentTagId: 4, Name: 'tshirt' },
  { TagId: 12, ParentTagId: 7, Name: 'longsleeve' },
  { TagId: 16, ParentTagId: null, Name: 'men' }
]

Expected outcome:

women > bottom  
women > top > shirt > longsleeve   
women > tshirt  
men  

Output data:

[
  {
    path: [ 
      { TagId: 2, ParentTagId: null, Name: 'women' },
      { TagId: 5, ParentTagId: 2, Name: 'bottom' }
    ]
  },
  {
    path: [
      { TagId: 2, ParentTagId: null, Name: 'women' },
      { TagId: 4, ParentTagId: 2, Name: 'top' },
      { TagId: 7, ParentTagId: 4, Name: 'shirt' },
      { TagId: 12, ParentTagId: 7, Name: 'longsleeve' }
    ]
  },
  {
    path: [
      { TagId: 2, ParentTagId: null, Name: 'women' },
      { TagId: 4, ParentTagId: 2, Name: 'top' },
      { TagId: 8, ParentTagId: 4, Name: 'tshirt' }
    ]
  },
  {
    path: [
      { TagId: 16, ParentTagId: null, Name: 'men' }
    ]
  }
]

Answer №1

Imagine your data input as a tree structure. The goal is to create the path to each individual leaf node. A leaf node is identified as a tag with a TagId that has no references as a ParentTagId in any other tag.

Here is a simplified approach:

  1. Go through all tags and form a set (a list with unique elements) of all ParentTagId values. In this case, the set would include: [2,4,7].
  2. To identify the leaf nodes, iterate through all tags and select the ones where the TagId is not found in the set obtained from step 1. For this dataset, those tags are: [5,8,12,16].
  3. Create a function called getTagById to retrieve a tag based on its id.
  4. Develop a recursive function to construct the path for each leaf node.
  5. Process all leaf nodes by adding the result of getPath([], leaf) to an array named paths. This array will contain the paths to each leaf represented as arrays of tags.
  6. Construct the final output using the information stored in paths.

Code snippet for step 1:

var parentTagIdSet = [];
for (var i = 0; i < originData.length; ++i) {
  var parentTagId = originData[i].ParentTagId;
  if (parentTagId != null && parentTagIdSet.indexOf(parentTagId) == -1) {
    parentTagIdSet.push(parentTagId);
  }
}

Code snippet for step 2:

var leaves = [];
for (var i = 0; i < originData.length; ++i) {
  var tag = originData[i];
  if (parentTagIdSet.indexOf(tag.TagId) == -1) {
    leaves.push(tag);
  }
}

Code snippet for step 3:

function getTagById(id) {
  for (var i = 0; i < originData.length; ++i) {
    var tag = originData[i];
    if (tag.TagId == id) {
      return tag;
    }
  }
  // Return null if the loop completes without finding a matching ParentTagId.
  return null;
}

Code snippet for step 4:

function getPath(path, currentTag) {
   if (currentTag == null) {
     // Reverse the path if incorrect ParentTagIds were encountered.
     path.reverse();
     return path;
   }
   path.push(currentTag);
   var parentId = currentTag.ParentTagId;
   if (parentId == null) {
     path.reverse();
     return path;
   } else {
     return getPath(path, getTagById(parentId));
   }
 }

Code snippet for step 5:

var paths = [];
for (var i = 0; i < leaves.length; ++i) {
  paths.push(getPath([], leaves[i]));
}

Answer №2

It is crucial to have an object structured as shown below...

class Trie implements IteratorAggregate
{
    protected $parent;
    protected $children = [];

    public function insert(Node $node)
    {
        $node->parent     = $this;
        $this->children[] = $node;
    }

    public function findById($id)
    {
        foreach($this->children as $childNode) {
            if ($childNode->TagId === $id) {
                return $childNode;
            }
            if ($childNode->hasChildren()) {
                $n = $childNode->findById($id);
                if ($n) {
                   return $n;
                }
            }
        }
    }

    public function hasChildren()
    {
        return (bool) count($this->children);
    }

    public function getIterator()
    {
        return new ArrayIterator($this->children);
    }
}

Furthermore, consider the node structure...

class Node extends Trie
{
    public function __construct(stdClass $obj)
    {
        foreach($obj as $p => $v) {
            $this->$p = $v;
        }
    }
}

To properly organize your list of objects, iterate over each node's object and then insert those with a null parent id into the tree's root. For nodes with children, insert them directly into their respective parents.

For instance,

$list = json_decode(<<<'JSON'
[ 
  { "TagId": 2, "ParentTagId": null, "Name": "women" },
  { "TagId": 5, "ParentTagId": 2, "Name": "bottom" },
  { "TagId": 4, "ParentTagId": 2, "Name": "top" },
  { "TagId": 7, "ParentTagId": 4, "Name": "shirt" },
  { "TagId": 8, "ParentTagId": 4, "Name": "tshirt" },
  { "TagId": 12, "ParentTagId": 7, "Name": "longsleeve" },
  { "TagId": 16, "ParentTagId": null, "Name": "men" }
]
JSON
);

$trie = new Trie;
/* Insert all of the parentless nodes */
foreach($list as $n => $obj) {
    if (!$obj->ParentTagId) {
        $trie->insert(new Node($obj));
        unset($list[$n]);
    }
}

/* Insert all of the child nodes */
foreach($list as $n => $obj) {
    $p = $trie->findById($obj->ParentTagId);
    if ($p) {
        $p->insert(new Node($obj));
        unset($list[$n]);
    }
}

By iterating over $trie, you will have access to all the parent nodes. Subsequently, you can explore deeper into the hierarchy by iterating over their children.

Answer №3

This JavaScript code may not be the most efficient or visually appealing, but it gets the job done.

    
    var input = [ 
      { TagId: 2, ParentTagId: null, Name: 'women' },
      { TagId: 5, ParentTagId: 2, Name: 'bottom' },
      { TagId: 4, ParentTagId: 2, Name: 'top' },
      { TagId: 7, ParentTagId: 4, Name: 'shirt' },
      { TagId: 8, ParentTagId: 4, Name: 'tshirt' },
      { TagId: 12, ParentTagId: 7, Name: 'longsleeve' },
      { TagId: 16, ParentTagId: null, Name: 'men' }
    ]
    
    var output = []
    var path = []
    function drill(el){
      path.push(el)
      var val = input.filter(function(e){return e.ParentTagId === el.TagId})
      if(val.length > 0)
        val.forEach(drill)
      else {
          var e = path[0]
          while(e = findParent(e))
            path.unshift(e)
          output.push({
            path: path
          })
          path = []
          return
      }
    }
    function findParent(el){
    return input.filter(function(e){return e.TagId === el.ParentTagId})[0]
    }
    input.filter(function(e){return e.ParentTagId === null}).forEach(drill)
    console.log(output)

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

An unforeseen issue occurred while trying to access an indexed element ID

I've recently started learning javascript and jquery, and encountered a problem while working on a script. The script is created by php code that reads lines from a file, processes them, and displays them using arrays. In addition, javascript validat ...

NPM is having trouble locating a shell script

An error is encountered when running npm run build: '.' is not recognized as an internal or external command, operable program or batch file. Here is the npm file that contains relevant scripts: "scripts": { "postinstall": "jspm instal ...

Display Material Popup in Angular before user leaves the page

My goal is to display an Angular Material Dialog Box (Popup window) when the user clicks the Chrome Window Close button. The Dialog modal should prompt the user if they want to save changes or cancel. However, the modal only appears for a brief moment and ...

Why does the Element.style.left property keep rejecting my input value?

I have encountered a problem with the positioning of elements, specifically with the 'left' property. I've designed a rectangular block using CSS and rotated it by 0.17 radians in JavaScript. Now, my aim is to make the block move diagonally ...

Using JMeter's Json Extractor to Parse Data from Multiple HTTP Requests

After configuring a ForEach Controller to run several HTTP requests, my goal is to extract JSON values from the response bodies of each request. However, when attempting to use a JSON Extractor PostProcessor on the HTTP Request, I am only able to retriev ...

Incorporating Local Storage into a To-Do List Application

I followed a tutorial from w3schools to create a custom task list, tweaking the code to fit my requirements. My goal is to ensure that when I click the save button in the toolbar at the top and then refresh the page, the added tasks are preserved. I&apos ...

"Maximizing Efficiency: Chaining Several Actions Using the JavaScript Ternary Operator

When the condition is true, how can I chain two operations together? a = 96 c = 0 a > 50 ? c += 1 && console.log('passed') : console.log('try more') I attempted chaining with && and it successfully worked in react, b ...

React-Troubleshooting list items and keys: A comprehensive guide to resolving common issues

I'm facing a challenge with generating unique key ID's for my list items. Even though I thought I had a good understanding of how unique keys function, it seems that I am mistaken. In the code snippet below, using key={index} or key={item} is no ...

Is it possible for the codebehind plugin to have a custom access path ending with

Is it possible to access a method as an action in Struts 2 with the Codebehind plugin? Since there is no struts.xml file and it works as action!method in the URL. I am simply curious about accessing a method How can Struts tags be used in a class? " ...

What is the best way to display or hide specific tables depending on the button chosen?

Being fairly new to JavaScript, I find myself unsure of my actions in this realm. I've successfully implemented functionality for three links that toggle visibility between different tables. However, my ideal scenario would involve clicking one link t ...

Using Facebook authentication in React Native

Currently developing a React Native app and aiming to incorporate Facebook login functionality. The back-end logic for user authentication is handled by an API in Node.js. Utilizing passport.js to enable users to log in using either Facebook or Email cre ...

Issue with Scrollspy Functionality in Bootstrap 4

Scrollspy feature isn't working in my code. <nav class="navbar navbar-expand-lg fixed-top navbar-dark" role="navigation"> <div class="container"> <a class="navbar-brand" href="#featured"><h1></h1></a> < ...

Error: Gulp could not parse the module

In my current project with Laravel 5.3, I have encountered some errors after installing node-uuid. { [Error: ./~/diffie-hellman/lib/primes.json Module parse failed: /var/www/html/filecloudprod/node_modules/diffie-hellman/lib/primes.json Unexpected tok ...

Generating random objects in a straight line with Javascript and HTML5: A step-by-step guide

In my current project, I am developing a game using Javascript/HTML5 (within a canvas element) that features two distinct types of objects (referred to as object type A and object type B) falling from the top of the canvas. The goal for players is to swip ...

Can you clarify the meaning of 'this' in an AngularJS controller?

index.html <body ng-controller="StoreController as s"> <h1 ng-click="s.changeValFunc()">{{s.carname}}</h1> <h2>{{s.carname}}</h2> </body> app.js var app = angular.module('store', []); app.controller(& ...

What does {``} denote in react-native programming?

During my participation in a collaborative project, I noticed that there is a significant amount of {' '} being used. For instance: <Text> {' '} {constant.Messages.PointText.hey} {this._user.first_name || this._user ...

Merge two arrays into a single array

I am working with an array that has the following structure: array ( [name] => name [description] => description here [first] => Array ( [0] => weight [1] => height ) [second] => Ar ...

What causes the error message "ng-model is undefined"?

Within my form, there are three angular-ui-bootstrap typehead elements <form> <div class="form-group"> <label for="fieldname" class="col-md-3 control-label">Name</label> <div class="col-md-6"> <input type="text ...

Having difficulty submitting a form with ajax, while accomplishing the same task effortlessly without ajax

I have been experimenting with submitting a form using ajax to the same .php file. When I submit the form without ajax directly (form action), the database gets updated. However, when I try the same process with ajax, there is no change in the database. H ...

Setting up jsdoc on a computer with slow internet access can be a bit tricky, but with

Recently, I have been working on some JavaScript code and utilized the sublime jsdoc plugin for commenting. Now, my goal is to generate documentation from these comments. The challenge lies in the fact that I am developing this JavaScript on a machine loca ...