What is the best way to insert an item into a tree structure when determining the appropriate level for insertion is necessary beforehand?

Currently, I am dealing with a tree-like object structure:

interface Node {
  id: number;
  name: string;
  children?: Node[];
}

NODE_DATA: Node[] = [
  {
    id: 1,
    name: 'A'
  },
  {
    id: 2,
    name: 'B',
    children: [
      {
        id: 3,
        name: 'C',
      },
      {
        id: 4,
        name: 'D',
      },
      {
        id: 5,
        name: 'E',
        children: [
          {
            id: 6,
            name: 'F'
          }
        ]
      }
    ]
  }
]

At this point, I am trying to create a function that takes an "id" of a Node as input and adds another Node ({id: 7, name: 'G'}) to the "children" array of the Node with the provided "id".

If anyone has any suggestions or hints on how this can be achieved, I would greatly appreciate it.

Answer №1

The objective is to create a function with the signature

declare function addChild(nodes: Node[], parentId: number, newNode: Node): void;
. This function will add the newNode to the children property of the node in the nodes tree that has an id matching the provided parentId. Here are some assumptions:

  • You aim to modify existing trees instead of making copies.
  • In case multiple nodes share the target id, adding the new node to the children of any one of them is acceptable (preferably the first encountered during tree traversal).
  • If no node in the tree matches the target id, leaving the tree unchanged is acceptable.

One possible approach to achieve this is through the following code snippet:

function addChild(nodes: Node[], parentId: number, newNode: Node): boolean {
  for (const node of nodes) {
    if (node.id === parentId) {
      (node.children ??= []).push(newNode);
      return true;
    }
    if (node.children) {
      const found = addChild(node.children, parentId, newNode);
      if (found) return true;
    }
  }
  return false;
}

This function utilizes recursion, which is a straightforward way to handle recursive data structures. By returning a boolean, it can signal whether the target node was found or not, allowing for early termination of tree traversal upon success.

For each node in the array supplied as input, we check its id against the specified parent id. If they match, we have located the node and proceed to add the new node to its children. Since the children property is optional, we may need to initialize it as an empty array before appending the new node. This initialization step can be streamlined using nullish coalescing assignment (??=) in the form:

(node.children ??= []).push(newNode);

If the current node is not the target node, the function recursively calls itself on the node's children array. If any of these recursive calls finds the target node, the search terminates early by returning true. Otherwise, the process continues until completion.

If the target node remains elusive after traversing the complete tree, the function returns false. While this outcome is not intended for user-invoked calls, it is expected within many subtrees of the original structure.


Let's put the function to the test:

addChild(NODE_DATA, 4, { id: 7, name: "G" });
console.log(JSON.stringify(NODE_DATA))
// Expected output:
// [{"id":1,"name":"A"},{"id":2,"name":"B","children":[{"id":3,"name":"C"},
//   {"id":4,"name":"D","children":[{"id":7,"name":"G"}]},
//   {"id":5,"name":"E","children":[{"id":6,"name":"F"}]}]}]

The test appears successful.

Playground link to code

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 Redux Toolkit Slice is encountering an issue where it generates the incorrect type of "WritableDraft<AppApiError> when the extraReducer is

I defined my initial state as MednannyAppointments[] for data and AppApiError for error. However, when I hover over state.error or state.data in my extraReducer calls, the type is always WritableDraft. This behaviour is confusing to me. Even though I have ...

Can a new class be created by inheriting from an existing class while also adding a decorator to each field within the class?

In the following code snippet, I am showcasing a class that needs validation. My goal is to create a new class where each field has the @IsOptional() decorator applied. export class CreateCompanyDto { @Length(2, 150) name: string; @IsOptional( ...

Retrieve all services within a Fargate Cluster using AWS CDK

Is there a way to retrieve all Services using the Cluster construct in AWS CDK (example in TypeScript but any language)? Here is an example: import { Cluster, FargateService } from '@aws-cdk/aws-ecs'; private updateClusterServices(cluster: Clus ...

Error message from OpenAI GPT-3 API: "openai.completions function not found"

I encountered an issue while trying to execute the test code from a tutorial on building a chat app with GPT-3, ReactJS, and Next.js. The error message I received was: TypeError: openai.completions is not a function This occurred when running the follow ...

Exception occurs when arrow function is replaced with an anonymous function

Currently, I am experimenting with the Angular Heroes Tutorial using Typescript. The code snippet below is functioning correctly while testing out the services: getHeroes() { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } H ...

The React component using createPortal and having its state managed by its parent will remain static and not refresh upon state modifications

I am facing a problem that can be seen in this live example: https://stackblitz.com/edit/stackblitz-starters-qcvjsz?file=src%2FApp.tsx The issue arises when I pass a list of options to a radio button list, along with the state and setter to a child compon ...

Unlocking the secret to accessing keys from an unidentified data type in TypeScript

The code snippet above will not compile due to an error with the email protection link. const foo: unknown = {bar: 'baz'} if (foo && typeof foo === 'object' && 'bar' in foo) { console.log(foo.bar) } An erro ...

When using TypeORM's findOneBy method, if the search result

In order for the entity to have both identifiers, I require it to possess the Id and the _id export class ScriptSequencesExecutionEntity { @PrimaryGeneratedColumn({ name: 'id' }) _id!: string; @ObjectIdColumn() id: number; @AutoMap() ...

Encountering issues while attempting to utilize pdf2json in a TypeScript environment

When attempting to import pdf2json (3.0.1) into my Node project using TypeScript, I encountered the following error: "Could not find a declaration file for module 'pdf2json'." I also tried installing @types/pdf2json for TypeScript but found tha ...

Utilizing TypeScript to import and export modules under a single namespace

Have a look at this query that's quite similar to mine: https://github.com/Microsoft/TypeScript/issues/4529 Consider the following code snippet: //exported imports export {ISumanOpts, IGlobalSumanObj} from 'suman-types/dts/global'; export ...

Managing errors with async/await in an Angular HttpClient function

I have been experimenting with an async/await pattern to manage a complex scenario that could potentially result in "callback hell" if approached differently. Below is a simplified version of the code. The actual implementation involves approximately 5 co ...

The 'wrapper' property is not present in the 'ClassNameMap<never>' type in Typescript

Hey there, I've been encountering a puzzling issue in my .tsx file where it's claiming that the wrapper doesn't exist. My project involves Material UI and Typescript, and I'm relatively new to working with Typescript as well as transiti ...

Get ready for 10 AM with the RxJS timer function

I am trying to figure out how to schedule a method in my code using rxjs/timer. Specifically, I want the method to run at precisely 10 AM after an initial delay of 1 minute. However, my current implementation is running every 2 minutes after a 1-minute d ...

Tips for confirming a sub string is present in an array using JavaScript/TScript

I am currently testing for the presence of a SubString within an array. In my test, I am asserting using: expect(classList).toContain('Rail__focused') However, I encountered the following error: Error: expect(received).toContain(expected // inde ...

What is the best approach for integrating a Material UI Autocomplete component with graphql queries?

Hello there! I'm currently working with React Typescript and trying to incorporate query suggestions into an Autocomplete Material UI component in my project. Below is a snippet of my GraphQL queries: Query Definition: import gql from 'graphql- ...

Develop an interface in TypeScript for intricate data structures

Displayed below is a variable that contains a collection of objects: scenes = { sky: { image: 'assets/1.jpg', points: { blue_area: { x: 1, y: 2 }, } }, blue_area: { image: & ...

What is the best way to verify both a null value and a length simultaneously within a template condition?

There is a data that can be null or an empty array, but the template should still be rendered if leaseApDto is not null or has a length greater than 0. I attempted to use the condition model.leaseApDto !== null || model.leaseApDto.length !=== 0, but they ...

Is it possible to create a combined header/declaration file in Golang within a single file?

My goal is to automatically generate Golang declaration files based on .json data. While with TypeScript I can consolidate types/declarations in one file using namespaces, it seems more complex to achieve the same with Golang packages and namespacing. In ...

Angular 6: A guide to dynamically highlighting navbar elements based on scroll position

I am currently building a single page using Angular 6. The page is quite basic, and my goal is to emphasize the navbar based on scrolling. Below is the code snippet I am working with: .sticky { position: sticky; top: 0; } #i ul { list-style-type: ...

Dispatch a websocket communication from a synchronous function and retrieve the information within the function itself

I am currently working on an Angular project and need guidance on the most effective approach to implement the following. The requirement is: To retrieve an image from the cache if available, otherwise fetch it from a web socket server. I have managed ...