Navigating through nested arrays in JavaScript

There is a JavaScript object structured like this:

let hogwartsHeirarchy = {
  Headmaster: [
    {
      name: "Professor Dumbledore",
      key: 1,
      Headmistress: [
        {
          name: "Minerva McGonagall",
          key: 2,
          StandByProfessor: [
            {
              name: "Rubeus Hagrid",
              subject: "Potions Master",
              key: 3,
              Professor: [
                { name: "Horace Slughorn", key: 4 },
                { name: "Severus Snape", key: 4 },
              ],
            },
            {
              name: "Alastor Moody",
              subject: "Defense Against the Dark Arts",
              key: 3,
              Professor: [
                { name: "Remus Lupin", key: 4 },
                { name: "Gilderoy Lockhart", key: 4 },
              ],
            },
          ],
        },
      ],
    },
  ],
};

I am trying to retrieve and display each node value [headmaster, headmastress,..] along with their child values. I have attempted different methods such as looping through the array using a for loop and recursion, but so far have not been successful in extracting any data from the nodes. Can someone provide assistance?

For example, I used the following function:

printArray(hogwartsHeirarchy);

function printArray(arr){
    for(var i = 0; i < arr.length; i++){
        if(arr[i] instanceof Array){
            console.log("true: ");

            console.log("intermediate one : ",arr[i]);

            printArray(arr[i]);

        }else{
            console.log("final one : ",arr[i]);
        }
    }
}

The desired output format is as follows:

Headmaster - name : Professor Dumbledore, key : 1
.
.
StandByProfessor - name : Robeus Hagrid, subject : Potion Master, key : 3
StandByProfessor - name : Alastor Moody, subject : Defence against the dark arts, key : 3
.
.
Professor - ...
Professor - ...
Professor - ...
Professor - ...

Answer №1

To improve the structure, I recommend organizing subordinates consistently under a single key for easier access. Additionally, I modified the hierarchy so that each node represents a person without any non-person objects at the top level. The variable name remains, now directly referring to Dumbledore.

let hogwartsHeirarchy =
  {
    name: "Professor Dumbledore",
    role: "Headmaster",
    key: 1,
    subordinates: [
      {
        name: "Minerva McGonagall",
        role: "Headmistress",
        key: 2,
        subordinates: [
          {
            name: "Rubeus Hagrid",
            role: "StandByProfessor",
            subject: "Potions Master",
            key: 3,
            subordinates: [
              { name: "Horace Slughorn", key: 4, role: "Professor" },
              { name: "Severus Snape", key: 4, role: "Professor"  },
            ],
          },
          {
            name: "Alastor Moody",
            role: "StandByProfessor",
            subject: "Defense Against the Dark Arts",
            key: 3,
            subordinates: [
              { name: "Remus Lupin", key: 4, role: "Professor" },
              { name: "Gilderoy Lockhart", key: 4, role: "Professor" },
            ],
          },
        ],
      },
    ],
  };
function visitStaff(staffMember) {
    if (staffMember.subordinates) {
        for (const subordinate of staffMember.subordinates) {
            visitStaff(subordinate);
        }
    }
    console.log("Staff member:", staffMember);
}
visitStaff(hogwartsHeirarchy);

When designing a data structure, consider how it will be accessed and its components. Here, nodes represent individuals, while relationships serve as graph edges.

The original code included an object { Headmaster: [...] } — what does this signify? It does not represent a person or a direct relationship, only defining Dumbledoor's job title. As such, it fits better as a property than standalone object.

Aligning objects to clearly represent entities aids in understanding their purpose within the structure.

Answer №2

When considering the data structure provided:

a) It is assumed that each type of "title" will have only one array, and
b) that array will contain objects with a similar structure to its parent

There is a possibility...

  1. to utilize the for..of loop to
  2. cycle through each key in an object and concatenate them into a string. Since there are arrays containing objects,
  3. I can iterate through these arrays and
  4. implement a recursive loop by calling the method within itself.

const hogwartsHierarchy = { Headmaster: [{ name: "Professor Dumbledore", key: 1, Headmistress: [{ name: "Minerva McGonagall", key: 2, StandByProfessor: [{ name: "Rubeus Hagrid", subject: "Potions Master", key: 3, Professor: [{ name: "Horace Slughorn", key: 4 }, { name: "Severus Snape", key: 4 }] }, { name: "Alastor Moody", subject: "Defense Against the Dark Arts", key: 3, Professor: [{ name: "Remus Lupin", key: 4 }, { name: "Gilderoy Lockhart", key: 4 }] }] }] }] };

function printAllWithChilds(obj, prevProp) {
  let listItem = (prevProp) ? ' -- ' + prevProp : '';
  
  for (const property in obj) {    // 1
    if (obj[property] instanceof Array) {
       obj[property].forEach((child_obj) => {                   // 3
         listItem += printAllWithChilds(child_obj, property);   // 4
       });
    } else {
      listItem += `, ${property}: ${obj[property]}`;            // 2
    }
  }
  
  return listItem;
}

let listStr = printAllWithChilds(hogwartsHierarchy);
console.log(listStr);

It would be beneficial to break down hogwartsHierarchy into smaller segments resembling a database structure where each individual has a unique primary_key. These arrays start to make more sense when examining the variable professors and how their corresponding belongs_to key links to the standbyprofessors, illustrating that "Horace Slughorn" belongs to "Rubeus Hagrid".

const headermaster = {
  name: "Professor Dumbledore",
  primary_key: 1
};

const headmistress = {
  name: "Minerva McGonagall",
  primary_key: 2,
  belongs_to: 1
};

const standbyprofessors = [{
    name: "Rubeus Hagrid",
    subject: "Potions Master",
    primary_key: 3,
    belongs_to: 2
  },
  {
    name: "Alastor Moody",
    subject: "Defense Against the Dark Arts",
    primary_key: 4,
    belongs_to: 2
  }
];

const professors = [{
    name: "Horace Slughorn",
    primary_key: 5,
    belongs_to: 3
  },
  {
    name: "Severus Snape",
    primary_key: 6,
    belongs_to: 3
  },
  {
    name: "Remus Lupin",
    primary_key: 7,
    belongs_to: 4
  },
  {
    name: "Gilderoy Lockhart",
    primary_key: 8,
    belongs_to: 4
  },
];

Answer №3

If you strip out known keys from the object and analyze the type hierarchy, then loop through the properties to retrieve the tuple consisting of type, name, subject, and key only if the type is present.

const
    getValues = (object, type) => [
        ...(type ? [`${type} - name : ${object.name}, ${object.subject ? `subject : ${object.subject}, ` : ''}key : ${object.key}`] : []),
        ...Object
            .keys(object)
            .filter(k => !['name', 'subject', 'key'].includes(k))
            .flatMap(k => object[k].flatMap(o => getValues(o, k)))
        ],
    hogwartsHierarchy = { Headmaster: [{ name: "Professor Dumbledore", key: 1, Headmistress: [{ name: "Minerva McGonagall", key: 2, StandByProfessor: [{ name: "Rubeus Hagrid", subject: "Potions Master", key: 3, Professor: [{ name: "Horace Slughorn", key: 4 }, { name: "Severus Snape", key: 4 }] }, { name: "Alastor Moody", subject: "Defense Against the Dark Arts", key: 3, Professor: [{ name: "Remus Lupin", key: 4 }, { name: "Gilderoy Lockhart", key: 4 }] }] }] }] };

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

Answer №4

According to the object model created by 1j01:

const magicSchoolHierarchy =
{  name: "Headmaster Dumbledore", role: "Headmaster", key: 1,
    subordinates: [{ name: "Minerva McGonagall", role: "Headmistress", key: 2,
        subordinates: [
          { name: "Rubeus Hagrid", role: "StandByProfessor", subject: "Potions Master", key: 3,
            subordinates: [
              { name: "Horace Slughorn", key: 4, role: "Professor" },
              { name: "Severus Snape", key: 4, role: "Professor"  }]},
          { name: "Alastor Moody", role: "StandByProfessor", subject: "Defense Against the Dark Arts", key: 3,
            subordinates: [
              { name: "Remus Lupin", key: 4, role: "Professor" },
              { name: "Gilderoy Lockhart", key: 4, role: "Professor" }]}]}]};
  
  
const visitStaff = (staffMember) => {
  const iter = (obj) => {
    const { name, role, key, subordinates } = obj;
    const subject = obj.subject ? `, subject : ${obj.subject}` : '';
    const line = `${role} - name : ${name}${subject}, key : ${key}`;
    const sublines = (Array.isArray(subordinates)) ? subordinates.flatMap(iter) : [];
    return [line, ...sublines];
  }
  return iter(staffMember).join('\n');
}
console.log(visitStaff(magicSchoolHierarchy));
.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

Unable to successfully display AJAX data on success

After successfully running my GradeCalc function in a MVC C# context with the grade parameter, I am facing an issue where the data is not displaying and the JavaScript alert pop up shows up blank. Can you assist me with this problem? $("#test").o ...

Can you explain how time.localtime() functions and provide some tips on how to use it effectively? Simple inquiry on understanding its operations

Can you explain the inner workings of time.localtime() to me? When I use this function, I can access the elements of the resulting tuple by indexing. For example: >>> time.localtime()[0] 2010 However, when I print the output of time.localtime(), ...

Tips for avoiding the automatic transition to the next slide in SwiperJS

How can I prevent the next button click in swiper based on my custom logic? I am using the swiperjs library within a Vue project and I need to stop users from swiping or clicking the next button to move to the next slide depending on certain conditions de ...

BufferGeometry does not have a defined position attribute

Is there a method to update the buffer geometry in order for an object position in the mesh to be duplicated into it? I have attempted to update the position matrices without success. ...

Time well spent with The Mighty Ajax

Within the success function for my post, I need to include the time posted. The original PHP code snippet that displays the time looks like this: echo "<br/><a href='#' class='subtleLink' style='font-weight:normal;'& ...

Combining two lists of lists with varying index lengths

Greetings, let's consider List one with the following headers: edges1=['a', 'g', 'w', 'Q'] list1=[[0, 2, 0, 9], [2, 0, 15, 2], [0, 15, 0, 7], [9, 2, 7, 0]] and edges2=['a', 'w', 'Q&a ...

Using ng-repeat with an AJAX-called JSON is not possible

I've been struggling with handling JSON data from an AJAX call and displaying it using ng-repeat. If you want to take a look at my code in a more organized way, I've shared it on http://jsfiddle.net/7quj9omw/. However, please note that the code ...

Basic jQuery request for JSON data

In an effort to send user data to a PHP script and display the results in an element, I am utilizing JSON. The process works smoothly until reaching the response stage. Despite receiving the correct results when logging to the console, attempting to append ...

The conventional method for including React import statements

I'm curious if there is a standard convention for writing import statements in React. For instance, I currently have the following: import React, { useState, FormEvent } from 'react'; import Avatar from '@material-ui/core/Avatar'; ...

Performing optimized searches in Redis

In the process of creating a wallet app, I have incorporated redis for storing the current wallet balance of each user. Recently, I was tasked with finding a method to retrieve the total sum of all users' balances within the application. Since this in ...

JQuery loader & amazing animations

I have implemented the wow.js plugin along with a jQuery preload tutorial from here. Although the preloader works fine, I am facing an issue where the animation by wow.js starts before all the elements on the page are preloaded. I am looking to modify my ...

Steps for making a dynamic number animation

Is there a way to create dynamic number changes when the user stops on a page using HTML, CSS, and JavaScript? I'd like the numbers to change as the user scrolls through the page until they come to a stop. I want the numbers to update quickly while t ...

Utilizing NextJS to retrieve cookie data within React components

Currently, I am working with a Next.js frontend and an Express backend. For authentication, I am utilizing cookies and have set up protected routes using Next.js middleware. The next step in my project involves accessing the cookie response within React ...

Error encountered while making an http get request for a node that returns JSON

I've been struggling with this issue for quite some time now. While I've come across similar problems on Stack Overflow, none of the suggested solutions seem to work for me. I keep encountering the following error message: undefined:1 SyntaxErro ...

Callbacks for AJAX responses that are asynchronous

After using AJAX in a limited and straightforward manner for some time, I find myself currently debugging a web application that heavily relies on JavaScript and JQuery for client-side coding. One issue that has caught my attention is the possibility of mu ...

Is there a way for me to include a prefix in the path where Vue pulls its component chunks from?

I recently incorporated VueRouter into my project and encountered an issue with the asset URL not being correct. Instead of displaying www.example.com/js/0.main.js The URL it generates is www.example.com/0.main.js Any suggestions on how to include the ...

Step-by-step guide on interacting with a JavaScript menu: Click to open the menu and close it by moving

My menu JavaScript function now opens with a click and closes with a click. I want it to open with a click and close when the mouse leaves the button. $("#theme_select").click(function() { if (theme_list_open == true) { $(".center ul li ul").h ...

Tips for limiting the size of image uploads to under 2 megabytes

I am trying to implement an html select feature that allows users to upload images. <div class="row smallMargin"> <div class="col-sm-6"> Attach Image </div> <div class="col-sm-6"> <input type="file" ng-model="image" accept=" ...

Testing an ExpressJS route and their corresponding controller individually: a step-by-step guide

I have set up an Express route in my application using the following code snippet (where app represents my Express app): module.exports = function(app) { var controller = require('../../app/controllers/experiment-schema'); app.route('/a ...

Is there a way to populate rows in a data table on subsequent pages using JavaScript?

Here is the ajax function I have written to change values of a row on one page while updating the total on another page of my data table. $.ajax({ type : "Post", contentType : "application/json; charset= ...