Develop a trail of links that reflect the structure of the nodes

The hierarchical structure of nodes is as follows:

{
       "nodes":[
          {
             "assetId":"cfe-3a2b-47e7-b7e9-e2e090ca0d34",
             "assetName":"IRCTC",
             "assetType":"Company"
          },
          {
             "assetId":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "assetName":"Northern Railway Fleet",
             "assetType":"Fleet"
          },
          {
             "assetId":"15-b76c-426c-a272-6485359c5836",
             "assetName":"Vande Bharat Express",
             "assetType":"Train"
          }
       ],
       "edges":[
          {
             "source":"cfe-3a2b-47e7-b7e9-e2e090ca0d34",
             "destination":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "relation":"HAS"
          },
          {
             "source":"32d9-05b8-4293-af55-2ee4617c6ffe",
             "destination":"15-b76c-426c-a272-6485359c5836",
             "relation": "HAS"
          }
       ]
    }
    

Essentially, the nodes contain a list of assets and the edges represent their relationships or mappings. To traverse the nodes, let's consider an example where I create a function called

generateTrail("15-b76c-426c-a272-6485359c5836");

This function should search for the given node ID in the edges object and fetch its parent.

The breadcrumb trail would be:

"IRCTC > Northern Railway Fleet > Vande Bharat Express"

Answer №1

To simplify the process, you can create two intermediate objects named nodeIdToName and nodeIdToParentId for easier lookup within a while loop:

const hierarchy = {
  nodes: [ { assetId:"cfe-3a2b-47e7-b7e9-e2e090ca0d34", assetName:"IRCTC", assetType:"Company" }, { assetId:"32d9-05b8-4293-af55-2ee4617c6ffe", assetName:"Northern Railway Fleet", assetType:"Fleet" }, { assetId:"15-b76c-426c-a272-6485359c5836", assetName:"Vande Bharat Express", assetType:"Train" } ],
  edges: [ { source:"cfe-3a2b-47e7-b7e9-e2e090ca0d34", destination:"32d9-05b8-4293-af55-2ee4617c6ffe", relation:"HAS" }, { source:"32d9-05b8-4293-af55-2ee4617c6ffe", destination:"15-b76c-426c-a272-6485359c5836", relation: "HAS" } ]
};

const nodeIdToName = hierarchy.nodes.reduce((acc, obj) => {
  acc[obj.assetId] = obj.assetName;
  return acc;
}, {});
const nodeIdToParentId = hierarchy.edges.reduce((acc, obj) => {
  acc[obj.destination] = obj.source;
  return acc;
}, {});

function createBreadcrumbs(id) {
  let breadcrumb = [];
  while(nodeIdToName[id]) {
    breadcrumb.push(nodeIdToName[id]);
    id = nodeIdToParentId[id];
  }
  return breadcrumb.reverse().join(' > ');
}

const breadcrumb = createBreadcrumbs("15-b76c-426c-a272-6485359c5836");

console.log({
  nodeIdToName,
  nodeIdToParentId,
  breadcrumb
});

Output:

{
  "nodeIdToName": {
    "cfe-3a2b-47e7-b7e9-e2e090ca0d34": "IRCTC",
    "32d9-05b8-4293-af55-2ee4617c6ffe": "Northern Railway Fleet",
    "15-b76c-426c-a272-6485359c5836": "Vande Bharat Express"
  },
  "nodeIdToParentId": {
    "32d9-05b8-4293-af55-2ee4617c6ffe": "cfe-3a2b-47e7-b7e9-e2e090ca0d34",
    "15-b76c-426c-a272-6485359c5836": "32d9-05b8-4293-af55-2ee4617c6ffe"
  },
  "breadcrumb": "IRCTC > Northern Railway Fleet > Vande Bharat Express"
}

Note: The presence of nodeIdToName and nodeIdToParentId in the output is purely for demonstration purposes.

Answer №2

  • To solve this problem, you can create two different `Map` instances. One will map each node's `assetId` to its corresponding `assetName`, while the other map will associate each edge's `destination` with its respective `source`.
  • Next, implement a function that accepts an `id` as input and retrieves the `source` along with the node name for the specified id.
  • If the `source` is not null, the function should recursively call itself and append the current crumb at the end. Otherwise, it should return the current crumb only.

const input = {nodes:[{assetId:"cfe-3a2b-47e7-b7e9-e2e090ca0d34",assetName:"IRCTC",assetType:"Company"},{assetId:"32d9-05b8-4293-af55-2ee4617c6ffe",assetName:"Northern Railway Fleet",assetType:"Fleet"},{assetId:"15-b76c-426c-a272-6485359c5836",assetName:"Vande Bharat Express",assetType:"Train"}],edges:[{source:"cfe-3a2b-47e7-b7e9-e2e090ca0d34",destination:"32d9-05b8-4293-af55-2ee4617c6ffe",relation:"HAS"},{source:"32d9-05b8-4293-af55-2ee4617c6ffe",destination:"15-b76c-426c-a272-6485359c5836",relation:"HAS"}]},
      nodeMap = new Map ( input.nodes.map(o => [o.assetId, o.assetName]) ),
      edgeMap = new Map ( input.edges.map(o => [o.destination, o.source]) )

function getCrumb(id) {
  const crumb = nodeMap.get(id),
        source = edgeMap.get(id);
        
  return source 
            ? [getCrumb(source), crumb].join(' > ')
            : crumb
}

console.log( getCrumb("15-b76c-426c-a272-6485359c5836") )
console.log( getCrumb("32d9-05b8-4293-af55-2ee4617c6ffe") )

Answer №3

I have devised a unique approach to tackle the problem using functional programming principles with an emphasis on an associative array data structure. Check out my solution below:

Start by creating a Map of doubly-linked list nodes based on the initial input. This will provide all the necessary relational data to solve the problem at hand and extract additional insights from the input:

function linkAssets (graph) {
  const map = new Map();

  for (const asset of graph.nodes) {
    map.set(asset.assetId, {value: asset});
  }

  for (const edge of graph.edges) {
    if (edge.relation === "HAS") {
      const previous = map.get(edge.source);
      const next = map.get(edge.destination);

      if (previous && next) {
        previous.next = next;
        next.previous = previous;
      }
    }
  }

  return map;
}

Next, utilize the map of linked list nodes to construct the breadcrumb path:

function createBreadcrumbs (
  graph,
  lastAssetId,
  {
    delimiter = " > ",
    transformFn = (asset) => asset.assetName,
  } = {},
) {
  const map = linkAssets(graph);
  const assetPath = [];
  let node = map.get(lastAssetId);

  while (node) {
    assetPath.unshift(transformFn(node.value));
    node = node.previous;
  }

  return assetPath.join(delimiter);
}

You can visualize how it works using this example:

const result = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836");
console.log(result); // "IRCTC > Northern Railway Fleet > Vande Bharat Express"

Furthermore, you have the flexibility to customize the output as per your requirements:

const result2 = createBreadcrumbs(input, "15-b76c-426c-a272-6485359c5836", {
  delimiter: " ➡️ ",
  transformFn: a => `${a.assetName} (${a.assetType})`,
});

console.log(result2); // "IRCTC (Company) ➡️ Northern Railway Fleet (Fleet) ➡️ Vande Bharat Express (Train)"

For a live demonstration and to play around with the code, refer to the TypeScript Playground link provided above.

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

Convert TypeScript-specific statements into standard JavaScript code

For my nextjs frontend, I want to integrate authentication using a keycloak server. I came across this helpful example on how to implement it. The only issue is that the example is in typescript and I need to adapt it for my javascript application. Being u ...

Guide to importing firebase-functions and firebase-admin using ES6 syntax for transpilation with Babel in Node 10

I've been working on my cloud functions in ES6 and using Babel to transpile them for the Node v10 environment. But, I've come across an odd issue. It seems that when I import firebase-functions like this: import functions from 'firebase-fu ...

retrieve data for chart from an AJAX request

I am looking to create a chart using amCharts and I have received some values from the server through an ajax call. Now, I need help in utilizing this data for my chart. Can anyone guide me on how to achieve this? var chart = am4core.create("chartdiv& ...

What is the best way to incorporate a popover into a fullcalendar event displayed on a resource timeline in Vue while utilizing BootstrapVue?

I need help adding a popover to an event in a resource timeline using fullcalendar/vue ^5.3.1 in Vue ^2.6.11 with ^2.1.0 of bootstrap-vue. Although I found some guidance on Stack Overflow, the solution involving propsData and .$mount() doesn't feel l ...

Progressively updating elements one by one leads to updates

I am currently working on a webpage where one element ('.item--itemprice') updates its text through a function that I don't want to modify. My goal is to have another element ('.header--itemprice') update its text to match the firs ...

Trouble with loading images on hbs/nodejs

I'm currently working on a web application using NodeJs and express-handlebars. However, I am facing an issue with images not displaying correctly on the HTML page that is being rendered using handlebars. Here is the structure of my app: The root fo ...

Arrange JSON information in an HTML table with distinct header rows for every data category

I have a JSON object with a key:value pair named callRoot. Some examples of values for this pair are @S, @C, and @W. There are multiple objects that share the same value and I want to create an HTML table head row at the beginning of each group and repeat ...

Is it no longer necessary to bind functions in React Component Classes?

Recently, I observed that when defining normal class component functions in React, there is no longer a need to bind them inside the class constructor. This means that even without using ES6 public class field syntax, you can simply pass these functions to ...

Meteor Infinity: the astronomy .save functionality seems to be malfunctioning

Encountering an issue where I am receiving a "post.save is not a function" error when trying to use the .save() function with astronomy v2. The error occurs when attempting to call the .save() function to insert a new document into the database using a Met ...

Combining values from multiple sets of 'radio buttons' in React to get a total

After analyzing the following dataset: const data = [ { id: 1, category: "category1", name: "N/A", price: 0, }, { id: 2, category: "category1", name: "Cheese", ...

Using jQuery to smoothly scroll to a position determined by a custom variable

Here's the script I am working with: $('.how-we-do-it .items div').on('click', function () { var $matchingDIV = $('.how-we-do-it .sections .section .content div.' + $(this).attr('class')); $matchingDIV. ...

What are some ways to enhance the opacity of a Material UI backdrop?

I'm looking to enhance the darkness of the material UI backdrop as its default appearance is not very dark. My goal is to make it dimmer and closer to black in color. ...

"Ionic application encountering issue with retrieving data from email inbox, resulting in undefined

I encountered an issue with creating a user account using Ionic Framework and Firebase. Oddly, the email box returns 'undefined' while the password box functions correctly despite being coded in a similar manner. Below is my HTML snippet: <io ...

Need some assistance in finding a way to input multiple values from multiple buttons into a single input field in JavaScript

Hello, I am looking for a little help with reading multiple values using multiple buttons such as 1, 2, and 3, and displaying the output in the input like '123' instead of just one number at a time. Concatenate numbers with every click. <inpu ...

Preserve the table's state even after submitting the form

My php page initially displays a table by default, which is: echo "<table class='tftable' border='1' id='table_L'>"; There is also another table: echo "<table class='tftable' border='1' id=&apos ...

The graph from Flot is not showing up, and there are no error messages

Recently, I have been experimenting with creating a graph plot using flot. However, I've encountered an issue where the graph is not displaying as expected. Despite using developer tools and JSlint to check for errors in my JavaScript code, both tools ...

Delete the designated column from the table

I am having difficulty with hiding and showing table columns using checkboxes. I need to eliminate the Mars column (in bold) along with its corresponding data (also in bold). Once the Mars column is removed, I want the Venus column and its data values to ...

Leveraging Lodash to retrieve values based on specific keys, even when certain keys are missing

How can I efficiently utilize Lodash while iterating through an array to extract and assign relevant values? I have an unfiltered array which contains ID and name[x].text elements. Some objects in the array may not have French text available, in which cas ...

Learn how to implement scrolling text using JavaScript and jQuery, where text slides by clicking on the previous and next icons

click here to see the image Is it possible to create a text slider that moves when clicking on previous and next icons? I want only 10 texts to be visible at a time, with the rest hidden. When clicked, all the texts should appear. Unfortunately, I don&apo ...

Ways to determine the numerical value of a specific word chosen by a user

I'm struggling to retrieve the position number of a word selected by a user. For instance If I have a simple paragraph with two words: Hi and Bob <p>Hi Bob</p> Therefore, logically Hi=1 and Bob=2. Now, if the user selects Bob, I want t ...