Identifying a loop within a hierarchy of JavaScript elements

I am facing a challenge with a list of elements that have unique IDs and parent IDs. My goal is to identify any loops in this hierarchical structure and pinpoint the ID that initiates the loop.

list = [
  {
    id: '1',
    parent: '2'
  },
  {
    id: '2',
    parent: '3'
  },
  {
    id: '3',
    parent: '4'
  },
    {
    //The loop starts at this ID
    id: '4',
    parent: '1'
  }
]

I have attempted to construct a tree using the given list, which functions correctly under normal circumstances but fails when a loop is present:

function treeify(list, idAttr, parentAttr, childrenAttr) {
    if (!idAttr) idAttr = 'id';
    if (!parentAttr) parentAttr = 'parent';
    if (!childrenAttr) childrenAttr = 'children';
    var treeList = [];
    var lookup = {};
    list.forEach(function(obj) {
        lookup[obj[idAttr]] = obj;
        obj[childrenAttr] = [];
    });
    list.forEach(function(obj) {
        if (obj[parentAttr] != null) {
            lookup[obj[parentAttr]][childrenAttr].push(obj);
        } else {
            treeList.push(obj);
        }
    });
    return treeList;
};

Despite my efforts, I have been unsuccessful in detecting loop occurrence within the hierarchy.

My objective is to not only identify the loop but also retrieve the ID of the element responsible for the loop, enabling me to rectify the underlying data structure.

Answer №1

To easily spot nodes that have been (re)visited while exploring their descendants, you can utilize a white-grey-black coloring technique. Here's a simplified version of your graph represented as a list of parent-child pairs:

graph = [
    [2, 1],
    [3, 2],
    [1300023, 3],
    [1, 1300023],
];

colors = {}

function visit(vertex) {
    if (colors[vertex] === 'black') {
        // black = visited and confirmed
        return; 
    }

    if (colors[vertex] === 'grey') {
        // grey = visited while its children are being visited
        // cycle detected!
        console.log('cycle', colors); 
        return; 
    }
    
    colors[vertex] = 'grey';

    graph.forEach(edge => {
        if (edge[0] === vertex)
            visit(edge[1]);
    });

    colors[vertex] = 'black'

}

visit(1)

For a great visual representation of this method in action, check out this resource:

Answer №2

To effectively identify circular references in a set of nodes, it is advisable to gather all nodes and their children in an object. Subsequently, you can filter through these nodes by utilizing an array of visited nodes for reference.

Within the infinite array lies all nodes that contribute to a circular reference issue.

function detectCircular(id, visited = []) {
    return visited.includes(id)
        || Object.keys(links[id]).some(k => detectCircular(k, visited.concat(id)));
}
var nodeList = [{ id: '1', parent: '2' }, { id: '2', parent: '3' }, { id: '3', parent: '4' }, { id: '4', parent: '1' }],
    links = {},
    circularNodes = [];
    
nodeList.forEach(({ id, parent }) => {
    links[parent] = links[parent] || {};
    links[parent][id] = true;
});


circularNodes = nodeList.filter(({ id }) => detectCircular(id));

console.log(links);
console.log(circularNodes);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

`The value of an element within an array changes automatically`

In my current setup, I have a traditional array where each element represents an HTML element. The issue arises when I manipulate these elements within the array; any changes made to the HTML element also reflect in the array automatically. However, I pref ...

Discover the procedure for extracting a dynamic value from JavaScript to PHP

Could the centerId value be utilized and transferred to a php variable? const data = { action: 'ft-add-member', maritalStatus: $('.ft-entry-relationship-info .ft-marital-status ul li.current a').data('dropdown' ...

Having trouble running the script, chrome error with message passing?

I've hit a roadblock while working on my Chrome extension and could use some assistance. The main issue I'm facing is getting the script to run when activated by the user through an on/off switch in the popup window. It seems like there might be ...

What is the best way to access a variable from a .js file?

Is there a way to access a variable defined in a JavaScript file from a Vue file and pass it to the Vue file? In the following code snippet, there is a template.js file and a contact.vue file. The template file converts MJML to HTML and saves the output to ...

Exploring the concept of JavaScript Variablesqueries

I need help understanding why the results are different in these three examples related to JavaScript. Case 1. var x = 5 + 2 + 3; document.getElementById("demo").innerHTML = x; Result: 10 Case 2. var x = 5 + 2 + "3"; document.getElementById("demo").in ...

React: Despite my efforts to return a value from render, nothing was actually returned

My current project involves creating nested components to display the dataset I have. export const MyComponent = (props) => { const groupMilestoneByYear = (data) => { // Take Milestone Data array as input and group it by Year let yearGroup ...

Display various v-dialog boxes with distinct contents in a vue.js environment

Hello there! I am currently working on customizing a Vue.js template and I have encountered an issue with displaying dynamic v-dialogs using a looping statement. Currently, the dialog shows all at once instead of individually. Here is the structure of my ...

JSON error: Encountered an unexpected token "o" while processing

My database table: TABLE `events` ( `event_id` INT(11) unsigned NOT NULL AUTO_INCREMENT, `event_title` VARCHAR(255) NOT NULL, `event_desc` TEXT, `event_location` VARCHAR(255) NOT NULL, `event_requirements` TEXT DEFAULT NULL, `event ...

Validating IDs by comparing them with one another. If the IDs do not match, an error message will be displayed. If they do match, the corresponding data will

Contents: Overview of the code's functionality. CODE Achievements. Bugs Expected vs. Actual Output Attempts to troubleshoot the errors 1. Overview of the Code's Functionality This system functions as a clock in and out mechanism utilizing an R ...

Try block must be followed by either a catch block or a finally

Currently, I am utilizing Node, Express with EJS view engine, nano for CouchDB, and encountering a perplexing error that I couldn't find any specific information about on Node or JavaScript via Stack Overflow or Google. The troublesome section of my c ...

The argument type does not match the parameter type partial<>

While attempting to validate my Ionic React form, I encountered an error when calling the validationSchema within the useForm method. The specific error message received is as follows: Argument of type '{ validationSchema: ......' is not assignab ...

TypeScript Yup schema validation combined with the power of Type Inference

I currently have a unique data structure as shown below: type MyDataType = | { type: "pro"; content: { signedAt: string; expiresOn: string }; } | { type: "default" | "regular"; content: { signed ...

Unable to fetch Twitter data using AJAX

Currently, I'm working on a web page that aims to display tweets from a specific city based on a user's search topic. The Twitter request is being sent successfully, with a response code of 200, and the response data is visible in the Chrome deve ...

JavaScript API for Tableau

Could you please clarify the functions described below? newViz = createTableauViz(containerDiv, url, options); function listenForMarkSelection() { newViz.addEventListener(tableau.TableauEventName.MARKS_SELECTION, handleMarksSelection); } funct ...

Using AngularJS: Implementing asynchronous $http.jsonp request through a service

I am currently developing a straightforward application that involves the following steps: 1. The user provides 2 parameters and clicks a button 2. Angular communicates with an external JAVA Servlet that sends back JSON data 3. The application displays the ...

Organizing your code with precision

I'm struggling with a project due to the poorly formatted code, making it almost impossible to read. Despite my attempts with various plugins and tools in VIM, Netbeans, Sublime Text 2, and Eclipse, the situation only seems to worsen. If anyone has ...

SWIFT functions with arrays and dictionary data structures

My goal is to transfer information to the second controller via a segue from the array: var gists = [Gists]() Here is how I have implemented the prepare(for segue: method: override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if se ...

Top technique for verifying the presence of duplicates within an array of objects

How can I efficiently check for duplicates in typescript within a large array of objects and return true or false based on the results? let testArray: { id: number, name: string }[] = [ { "id": 0, "name": "name1" }, ...

Creating a Vue.js component during the rendering process of a Laravel Blade partial view

In my Vue.js project, I have a component that is used in a partial view called question.blade.php: {{--HTML code--}} <my-component type='question'> <div class="question">[Very long text content...]</div> </my-component& ...

Required inputs do not disrupt the form's action flow

Here is the HTML code that I am working with: function document_save_changes(){ if (is_key_dirty == true){ var elm = document.getElementById('set_doc_button'); key_change_warning(elm, 'D'); return; } if (document_save_warning('A ...