I have a javascript object as follows :
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 want to print/get each of the node value [headmaster, headmastress,..] and their corresponding child values. I tried various methods like looping through the array using a for loop, recurse etc, but unfortunately I am not able to get any value out of the nodes. Please help.
e.g : I used this :
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 values can be shown in this format:
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 - ...
I would suggest restructuring so that the subordinates are always accessed with the same key, and thus can be visited very simply. I also made it so every node is a person, there's no object at the top that isn't a person. I left the variable name, but it now refers to Dumbledore directly.
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 setting up a data structure, it's important to think about how it will be accessed, and what are its defining parts. In this case, there are people, which are the nodes, and (subordinate) relationships, which are the edges of the graph.
In your original code, you had an object { Headmaster: [...] } — what does it represent? is it a person? no; is it a relationship? kind of, but no. It defines something about Dumbledoor, that he's the Headmaster, but not who or what he's the Headmaster of. So it's really just describing the role/job title of Dumbledoor, so it makes more sense as a property of the person. It's redundant as an object.
It helps to align your objects so they all represent something. You should be able to describe what each object and array is.
You could remove known keys from the object and get the type hierarchy then iterate the property and return the tupel of type, name, subject and key only if type exists.
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; }
Given the data structure:
a) I assume that there will be only one array in each type of "title", and
b) that array will contain a list of objects of a similar structure as it's parent
It's possible ...
for..of in order toconst 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);
I would honestly split up hogwartsHierarchy into smaller bits, following a kind of database structure, where primary_key is unique for each individual. These arrays doesn't make much sense, until you look at the variable professors and how their respectively belongs_to key corresponds to the standbyprofessors, where you can see 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
},
];