What is the process for transforming a plain JavaScript array into a hierarchical graph format?

Is there a way to transform this flat json construct:

[
    ["a","b","c"],
    ["a","b","d"],
    ["c","b","e"],
    ["c","b","f"]
]

Into the specified graph structure utilizing javascript?

{"uri": "a", "subItems": [
    {"uri": "b", "subItems": [
        {"uri": "c", "subItems": [
            {"uri": "b", "subItems": [
                {"uri": "e"},
                {"uri": "f"}
            ]}
        ]},
        {"uri": "d"}
    ]}
]}

Answer №1

This code snippet is designed to bring you very close to your desired outcome. By wrapping the JSON result in an array, the getNode function is simplified, although you can opt to directly target the [0] index of the array instead. Initially, there was an attempt to adhere to JSLint standards (hence the use of i = i + 1 instead of i++), but this approach was abandoned midway for the sake of clarity and cleanliness. ;)

http://jsfiddle.net/Zcyca/

var i, j, k, arr = 
[
    ["a","b","c"],
    ["a","b","d"],
    ["c","b","e"],
    ["c","b","f"]        
];

var results = [];
var last = results;

for(i = 0; i < arr.length; i = i + 1) {
    var subArr = arr[i];  
    var parentURI = subArr[0], middleURI = subArr[1], childURI = subArr[2]; 
    var parent, middle, child;

    // Find parent or create parent
    parent = getNode(results, parentURI);        
    if(parent === null) {
        results.push({"uri": parentURI, "subItems": []});
        parent = results[results.length-1];
    }        
    if(typeof parent["subItems"] === "undefined") {
        parent["subItems"] = [];
    }

    // Find middle or create middle
    middle = getNode(parent["subItems"], middleURI);
    if(middle === null) {
        parent["subItems"].push({"uri": middleURI, "subItems": []});
        middle = parent["subItems"][parent["subItems"].length-1];        
    }
    if(typeof middle["subItems"] === "undefined") {
        middle["subItems"] = [];
    }    

    // Find child or create child 
    child = getNode(middle["subItems"], childURI);
    if(child === null) {
        middle["subItems"].push({"uri": childURI});
        //child = middle["subItems"][middle["subItems"].length-1];            
    }
}

document.write(JSON.stringify(results));

function getNode(arr, uri) {
    var node = null;

    (function recurseArr(arr) {
        for(var i = 0; i < arr.length; i = i + 1) {
            var obj = arr[i];
            if(obj["uri"] === uri) {
                node = arr[i];
                break;   
            } else if(typeof obj["subItems"] !== "undefined") {  
                recurseArr(obj["subItems"]);
            }
        }
    })(arr);      

  return node;  
}

Answer №2

It appears there is no straightforward solution.

I found myself unsure of how to proceed in situations where an additional match needs to be located. For instance, if you were to insert ["b", "e", "b"], should the "b" be placed on the second level or the fourth?

http://jsfiddle.net/qVFCe/3/

var data = [
["a", "b", "c"],
["a", "b", "d"],
["c", "b", "e"],
["c", "b", "f"]
];

var group = null;

var baseStructure = {
    "uri": null,
    "subItems": []
};


function find(parent, uri) {
    for (var i = 0; parent.subItems && i < parent.subItems.length; i++) {
        if (parent.subItems[i].uri == uri) {
            return parent.subItems[i];
        }
    }
    return null;
}

function findRecursive(parent, uri) {
    var i, obj;
    //look in children
    for (i = 0; parent.subItems && i < parent.subItems.length; i++) {
        obj = find(parent.subItems[i], uri);
        if (obj !== null) {
            return obj;
        }
    }
    //look recursively in children
    for (i = 0; parent.subItems && i < parent.subItems.length; i++) {
        obj = findRecursive(parent.subItems[i], uri);
        if (obj !== null) {
            return obj;
        }
    }
    return null;
}


for (var i = 0; (group = data[i]); i++) {
    var current = baseStructure;
    for (var j = 0; j < group.length; j++) {
        var obj = find(current, group[j]);

        if (obj === null && j === 0) {
            obj = findRecursive(current, group[j]);
        }

        if (obj === null) {
            //create a new one if not found
            obj = {
                uri: group[j]
            };
            if(current.subItems === undefined)
            {
                current.subItems = [];
            }
            current.subItems.push(obj);
        }
        current = obj;
    }
}

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 an auto-incrementing ID within Firebase's real-time database

How can I create an automatic incrementing ID for entries in a Firebase database? The first item should have an ID of 1, and the second one should be 2. var database = firebase.database(); var userDetails = database.ref("Article"); userDetails. ...

Animating a JQuery Slider using code from scratch

I'm attempting to dynamically alter/animate a JQuery slider. In this scenario, there are two arrays present: one for the values that need to be modified and another for the durations between modifications. By monitoring the console, you'll observ ...

Customize the CSS class from the DateTimePicker NPM module when using it in a React project

Can I customize a style from a CSS file in an NPM package? I am facing difficulty in removing the black border from the DateTimePicker NPM package. Here is my code snippet; import { Controller, useForm } from 'react-hook-form' import DateTimePi ...

Exploring the benefits of leveraging TypeScript with AWS NodeJS for improved stacktrace visibility over traditional JavaScript

I'm contemplating the idea of transitioning my existing JavaScript codebase to incorporate TypeScript in NodeJS. One aspect that I am concerned about is being able to view the stack trace in AWS CloudWatch (request log) in case an error occurs during ...

Preventing undesired form submissions in HTML and JavaScript

My question might be simple, but it's what I have in mind. When working with two buttons in HTML - one for form submission and the other to trigger a JavaScript event - both buttons end up submitting the form. How can I make sure the second button onl ...

Having trouble with protractor's sendKeys function when trying to interact with md-contact-chips

Does anyone know how to set a value using sendKeys in Protractor for md-contact-chips? I attempted to use element(by.model('skills')).sendKeys('Java'); but it doesn't seem to be working. Any suggestions on how to approach this in ...

Tips for sending attributes to jQuery autocomplete

I'm facing a major issue with implementing a jquery autocomplete feature, and JavaScript isn't my strong suit. Currently, I'm using the jquery.auto-complete plugin available at: https://github.com/Pixabay/jQuery-autoComplete, which is an up ...

Modify mesh in three.js scene

Is there a way to dynamically change a mesh in a group triggered by a button click? I am loading an external .obj file: loader.load( obj, function ( object ) { createScene( object, mod.tipo, pid, cor.replace("#","0x") ); }); and adding it to a gro ...

"Enhancing JSON elements on the fly with WSO2's enrich mediator: A step-by-step guide

I attempted to utilize the following configuration: <property name="messageType" scope="axis2" type="STRING" value="application/xml"/> <property expression="get-property('orderSourceSF')& ...

Creating clickable phone numbers in JSON elements for browser display to enable direct calling action

There is a Phone.json file with the following contents: { "Call": "Hi, Please contact the custom care at (119)239-9999 for further discussions" }, { "Call": " For emergency dial 911 as soon as possible" } The goal is to dis ...

Guide to successfully formatting and outputting JSON on a Jersey RESTful web service

After incorporating a Jersey library and a media JSON library into my application, the XML configuration looks like this: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3. ...

Troubleshooting: Difficulty displaying intricate JSON model data correctly within a UITableView in Swift

My JSON data is complex with nested values, but I have correctly implemented it and the data values are stored in the model. However, I am facing an issue where only the first 12 values are being displayed instead of all 71 data values. It seems that there ...

What is the best way to move the Grid upward when the above content is not visible?

Let me demonstrate what I have been working on. Currently, I am creating a weather application to explore the functionalities of https://material-ui.com/. I am attempting to prototype an animation inspired by Google Flights, which can be seen here: https: ...

Tips for utilizing li tags to mimic the functionality of a table

I am looking to organize a list of li tags within a ul in a specific order, similar to a table layout I have created. The table <style type="text/css> .tg {border-collapse:collapse;border-spacing:0;width: 300px; height: 300px;} .tg td{font-fami ...

Tips for executing a script while updating npm version

Can a script be executed during the npm version command, after the release number has been incremented but before the git tag is created and pushed? ...

Issues with Facebook Messenger Quick Replies not displaying when generated from Dialogflow Webhook Response

I am currently facing an issue with implementing QR buttons in my FBM bot app. The webhook is functioning properly and text messages are being returned to FBM without any problems. However, when I input the JSON for the QR buttons, they do not appear in F ...

Customizing the returned data in Jquery autocomplete

I have the following code snippet: $(document).ready(function () { if ($('#au').length <= 0) { return; } var $project = $('#au'); $project.autocomplete({ minLength: 4, source: function (reque ...

Encountering the "potential null object" TypeScript issue when utilizing template ref data in Vue

Currently, I am trying to make modifications to the CSS rules of an <h1> element with a reference ref="header". However, I have encountered a TypeScript error that is preventing me from doing so. const header = ref<HTMLElement | null> ...

Guide to making a language selection wrapper using a gist script

Currently, I have a Gist file that is written in various languages but all serve the same purpose. As a result, I am interested in developing a language selection feature similar to what is found in the Google docs documentation. https://i.stack.imgur.com ...

The AJAX event is failing to send data

When using two ajax calls, the first one populates a dropdown box successfully. However, the second ajax call utilizes a change event function to list product details with images whenever a dynamically populated item from the dropdown is clicked. In the c ...