Creating a nested array of objects using a recursive function

How can I utilize my getChildren() function to create a larger function that takes my two main arrays objs and objRefs, and generates a single array of objs showcasing their parent/child relationship?

Below are the two primary data arrays:

const objs = [
    { name: "Kevin", age: 5, id: 1 },
    { name: "Matt", age: 53, id: 5 },
    { name: "Marry", age: 30, id: 2 },
    { name: "Leslie", age: 21, id: 3 },
    { name: "Sarah", age: 46, id: 4 },
    { name: "Heather", age: 37, id: 6 },
    { name: "Cory", age: 19, id: 7 },
]

const objRefs = [
    { parent_id: 5, obj_id: 7 }, // cory child of matt
    { parent_id: null, obj_id: 6 }, // matt root
    { parent_id: null, obj_id: 4 }, // sarah root
    { parent_id: null, obj_id: 5 }, // heather root
    { parent_id: 5, obj_id: 3 }, // leslie child of matt
    { parent_id: 4, obj_id: 2 }, // mary child of sarah
    { parent_id: 3, obj_id: 1 }, // kevin child of leslie
]

The objective is to execute a function called getFamilyTree() which should give me the following output...

const tree = [
    {
        id: 5,
        name: "Matt",
        age: 53,
        children:[ 
            {
                id: 3,
                name: "Leslie",
                age: 21,
                children:[ 
                    {
                        id: 1,
                        name: "Kevin",
                        age: 5,
                        children:[ ]
                    }
                ]
            },
            {
                id: 7,
                name: "Cory",
                age: 19,
                children:[ ]
            }
        ]
    },
    {
        id: 6,
        name: "Heather",
        age: 37,
        children:[ ]
    },
    {
        id: 4,
        name: "Sarah",
        age: 46,
        children:[ 
            {
                id: 2,
                name: "Marry",
                age: 30,
                children:[ ]
            }
        ]
    }
]

I have a function that returns all children for a given parent node id, but I'm uncertain how to structure a function that will return the entire tree as shown in my example.

function getChildren(parent_id) {
    let children = []
    for (var i = 0; i < objRefs.length; i++) {
        const ref = objRefs[i]
        if (ref.parent_id === parent_id) {
            const obj = objs.find(obj => {
                return obj.id === ref.obj_id
            })
            children.push(obj)
        }
    }
    return children
}

function getFamilyTree() {
    let result = []
    ... // build recursive family tree
    return result 
}

Answer №1

Your solution does not require a recursive function to build the family tree structure. Instead, you can achieve a decent time complexity by storing all the objects in a Map or array (if the IDs are sequential) and then iterating over objRefs to create the relations accordingly:

Here's an example code snippet demonstrating this approach:

const objs = [
    { name: "Kevin", age: 5, id: 1 },
    { name: "Matt", age: 53, id: 5 },
    { name: "Marry", age: 30, id: 2 },
    { name: "Leslie", age: 21, id: 3 },
    { name: "Sarah", age: 46, id: 4 },
    { name: "Heather", age: 37, id: 6 },
    { name: "Cory", age: 19, id: 7 },
]

const objRefs = [
    { parent_id: 5, obj_id: 7 }, // Cory child of Matt
    { parent_id: null, obj_id: 6 }, // Matt root
    { parent_id: null, obj_id: 4 }, // Sarah root
    { parent_id: null, obj_id: 5 }, // Heather root
    { parent_id: 5, obj_id: 3 }, // Leslie child of Matt
    { parent_id: 4, obj_id: 2 }, // Marry child of Sarah
    { parent_id: 3, obj_id: 1 }, // Kevin child of Leslie
]

function getFamilyTree(objs, objRefs){
    const tree = []
    const map = new Map(
        objs.map(e => [e.id, { ...e, children: [] }])
    )
    for(const {parent_id, obj_id} of objRefs){
        if(parent_id === null){
            tree.push(map.get(obj_id))
        } else {
            map.get(parent_id).children.push(map.get(obj_id))
        }
    }
    return tree
}

const tree = getFamilyTree(objs, objRefs)
console.log(tree)

Answer №2

In my opinion, the getChildren function may not be necessary for constructing your tree. Utilizing Maps could prove to be more advantageous:

const people = [
    { name: "Alice", age: 25, id: 1 },
    { name: "Bob", age: 30, id: 2 },
    { name: "Charlie", age: 35, id: 3 },
    { name: "David", age: 40, id: 4 },
]

const relationships = [
    { parent_id: null, person_id: 1 }, // Alice is a root node
    { parent_id: 1, person_id: 2 }, // Bob is Alice's child
    { parent_id: 1, person_id: 3 }, // Charlie is also Alice's child
    { parent_id: 3, person_id: 4 }, // David is Charlie's child
]

function buildFamilyTree(){
  const nodesMap = new Map()

  // Create initial nodes with empty children arrays
  people.forEach(person => nodesMap.set(person.id, {...person, children: []}))

  // Link nodes based on parent-child relationships
  relationships.forEach(rel => {
    const parent = nodesMap.get(rel.parent_id)
    parent.children.push(nodesMap.get(rel.person_id))
  })
  
  // Identify and mark the root nodes
  relationships.filter(rel => rel.parent_id === null).forEach(rel => {
    const person = nodesMap.get(rel.person_id)
    person.root = true
  })

  return Array.from(nodesMap.values()).filter(person => person.root)
}

document.write(JSON.stringify(buildFamilyTree(), null, 4))

Note: This solution might vary slightly from what was requested by the original poster. Nina mentioned in a comment that an explicitly recursive approach might be needed, but I'm presenting this alternative using Maps for reference.

Answer №3

To establish connections between individuals and their relationships, one could utilize an object as a reference point and then create a mapping of nodes along with their respective children.

const
    getChildren = parent => (references[parent] || []).map(id => ({
        ...nodes[id],
         children: getChildren(id)
    })),
    people = [{ name: "Kevin", age: 5, id: 1 }, { name: "Matt", age: 53, id: 5 }, { name: "Marry", age: 30, id: 2 }, { name: "Leslie", age: 21, id: 3 }, { name: "Sarah", age: 46, id: 4 }, { name: "Heather", age: 37, id: 6 }, { name: "Cory", age: 19, id: 7 }],
    children = [{ parent_id: 5, obj_id: 7 }, { parent_id: null, obj_id: 6 }, { parent_id: null, obj_id: 4 }, { parent_id: null, obj_id: 5 }, { parent_id: 5, obj_id: 3 }, { parent_id: 4, obj_id: 2 }, { parent_id: 3, obj_id: 1 }],
    nodes = Object.fromEntries(people.map(o => [o.id, o])),
    references = children.reduce((r, { parent_id, obj_id }) => ((r[parent_id] ??= []).push(obj_id), r), {}),
    tree = getChildren(null);
    
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

This methodology involves the use of a singular loop for processing the data within the children array.

const
    getTree = (people, children, root) => {
        const
            nodes = Object.fromEntries(people.map(o => [o.id, o])),
            t = {};

       children.forEach(({ parent_id: p, obj_id: id }) => 
           ((t[p] ??= {}).children ??= []).push(Object.assign(t[id] ??= {}, nodes[id]))
       );
       return t[root].children;
    },
    people = [{ name: "Kevin", age: 5, id: 1 }, { name: "Matt", age: 53, id: 5 }, { name: "Marry", age: 30, id: 2 }, { name: "Leslie", age: 21, id: 3 }, { name: "Sarah", age: 46, id: 4 }, { name: "Heather", age: 37, id: 6 }, { name: "Cory", age: 19, id: 7 }],
    children = [{ parent_id: 5, obj_id: 7 }, { parent_id: null, obj_id: 6 }, { parent_id: null, obj_id: 4 }, { parent_id: null, obj_id: 5 }, { parent_id: 5, obj_id: 3 }, { parent_id: 4, obj_id: 2 }, { parent_id: 3, obj_id: 1 }],
    tree = getTree(people, children, null);
    
console.log(tree);
.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

Response from Socket.io: What is the best way for the server to respond to all clients after receiving input from multiple clients?

Currently diving into the realm of node.js, express, and socket.io Thrilled to report that my server is up and running, successfully connecting to the browser via localhost:3000 Communication between client and server is seamless both ways. Now, onto th ...

Utilizing an object as a prop within React-router's Link functionality

Looking for a solution to pass the entire product object from ProductList component to Product component. Currently, I am passing the id as a route param and fetching the product object again in the Product component. However, I want to directly send the ...

Creating a custom scrollbar using JavaScript

I am attempting to create a custom scrollbar using JavaScript (jQuery) and Divs for a TV app. I am unable to use plugins due to the limitations of the TV. Despite looking at code from various plugins, I have not been successful. Here is what I have so far ...

Typescript is failing to compile classes in a reliable sequential order

In my MVC 5 project, I am using TypeScript and angular. There are three TS files: Controller1.ts, Controller2.ts, and app.ts. The issue arises when I compile the program for the first time - everything usually compiles correctly in the expected order. Howe ...

Discovering nearby intersections within 2 sets of arrays

Imagine having these two arrays: var a = [126, 619, 4192, 753, 901]; var b = [413, 628, 131, 3563, 19]; Is there a way to identify elements in both arrays that are close to each other by a certain percentage? Let's say we have the following functio ...

Monitor for the specific parameter in the incoming GET request

My application is using the POST method to submit jobs remotely. After submitting a job, I receive a unique job ID from the POST request that allows me to check the status of the job using a GET request. $http.get('http://localhost:8090/jobs/'+i ...

What steps can I take to resolve the issue of a Promise that remains in a

Currently, I am working on implementing a protected route feature in React. My goal is to modify the result variable so that it returns a boolean value instead of a promise without converting the ProtectedRoute function into an async function: import Reac ...

Global variables become undefined after utilizing jQuery's getScript() method for assignment

I have a few global variables named var1, var2, and so on... Instead of immediately initializing these variables, I wait until later to instantiate them using jQuery from a constructor located in a separate javascript file. However, after this instantiat ...

Generate a c3 chart illustrating a bar graph incorporating offset and duration

How can I accurately display daily working hours for a person, using input data of date and duration worked in seconds? I am facing difficulty determining the offset for the duration displayed on the graph. For instance, if a person starts work at 9:30 am ...

The options object provided for Ignore Plugin initialization in Webpack 5.21.2 does not conform to the API schema, resulting in an error

Here is the setup of my webpack.config.js on a backend server running webpack version 5.21.1: /* eslint-disable */ const path = require('path'); const webpack = require('webpack'); module.exports = { target: 'node', modul ...

Creating a javascript function to update content on click

Recently, I've been designing a webpage and encountered an issue. I want the text in a specific area to change whenever a user clicks on a link. Below is the code snippet related to the section I want to modify using a JavaScript function. <div id ...

Having trouble with expressJs router.post() not functioning properly with multiple middleware, resulting in an [object Undefined] error

I have been working on developing a REST API for my users, utilizing express-validator for validation before adding the user to the database. However, I encountered an issue while chaining my middleware in the router.py file which resulted in the error Err ...

Issues with the drop-down menu in the <s:select> element arise when attempting to set the

While utilizing a Map to populate the Struts2 tag <s:select >, I have noticed that when the form is submitted multiple times, a blank line is added at the end of the list. For example, if the Map contains 2 key-value pairs, it displays 3 records and ...

Error: The JavaScript function you are trying to use is not defined

Hi there, I'm new to javascript and angularjs. I've created a function in my controller to open a website when clicking on a button. However, I'm encountering an error message saying ReferenceError: openWebsite is not defined when trying to ...

The React JSX error message "Maximum update depth exceeded" occurs when there

It appears that I am facing an issue of creating an infinite loop while passing props from one class to another. Despite ensuring that the buttons are correctly bound and trigger only once, the problem persists without any solution in sight after thorough ...

Can you tell me the appropriate type for handling file input events?

Using Vue, I have a simple file input with a change listener that triggers the function below <script setup lang="ts"> function handleSelectedFiles(event: Event) { const fileInputElement = event.target as HTMLInputElement; if (!fileInp ...

Using AJAX, JQuery, and PHP to convert a given name to match the columns in a query, utilizing the data sent

One thing that I'm wondering about is how PHP handles my ajax requests. For example, consider the following code snippet: $("#addUser").on('click', '.btnAddSubmitFormModal', function() { $.post("add.php", { ...

Determining the height of the first element in jQuery

I am dealing with multiple elements that share the same class but have different heights. The class 'xyz' is only for styling borders, as shown below: <div class='xyz'></div> //1st element height=10px <div class='xy ...

The filtering function stops working after the initial use

As I develop an app using React and Redux, my goal for the following code snippet is to function as a reducer within the main application. I have imported a filterData function, which works seamlessly the first time any Action type is selected. However, it ...

Selection Change Event for Dropdown Menu

Just starting to learn JavaScript and currently working with 3 select elements on a JSP page: <select id="railwayServiceList" name="railwayService_id" onchange="changeCompaniesCombo()"></select> <select id="companyList" name="company_i ...