What is the most efficient way to recursively calculate the total number of devices in a group within a nested array?

const data= [
  {
    "category": "cat1",
    "items": ["item5","item6"],
    "subcategories": [
      {
        "category": "cat11",
        "items": ["item1","item2","item3","item4"],
        "subcategories" [
          {
            "category": "cat111",
            "items": ["item7","item8","item9","item0"],
            "subcategories" []
          },
          {
            "category": "cat112",
            "items": ["item7","item8","item9","item0"],
            "subcategories" []
          }
        ]
      },
      {
        "category": "cat12",
        "items": ["item1","item2","item3","item4"],
        "subcategories" [
          {
            "category": "cat121",
            "items": ["item7","item8","item9","item0"],
            "subcategories" []
          }
        ]
      }
    ]
  }
]

This is a data structure with nested subcategories and items. The goal of the recursive function in TypeScript is to determine the total count of items under each category.

For instance:

cat1 : 22
cat11 : 12
cat11 : 8
cat121 : 4

An implementation has been attempted but it does not provide the desired results.

this.getItemCount(this.data, 0);


/**
     * Recursive method to calculate the number of items in a category
     */
    getItemCount(data: any[], itemCount: number) {
        data.forEach((category) => {
            itemCount = itemCount + category.items.length;
            if(category.subcategories.length) {
                this.getItemCount(category.subcategories, itemCount);
            }
            category.count = itemCount;
            itemCount = 0;
        });
    }

Answer №1

An interesting aspect in JS/TS is that arguments are passed by value, leading to a situation where modifying a parameter within a function does not affect its value outside the function. This applies especially to primitive types like numbers, such as the 2nd parameter devcount in your code snippet.

Instead of attempting to alter the argument value directly, a better approach would be to simply return it from the function:

getdevicesCount(array: any[]) {
  let total = 0;
  array.forEach((group) => {
    group.count =
      group.devices.length
      + this.getdevicesCount(group.children);
    total += group.count;
  });
  return total;
}

Answer №2

To calculate all counts for each key in an object, you'll need to modify your function. Here's an example of a function that returns the count and populates the object at the same time:

function getCounts(array) {
    let counts = {}

    function calculateCount(obj) {
        counts[obj.groupId] = obj.devices?.length ?? 0
        for (let child of (obj.children ?? []))
            counts[obj.groupId] += calculateCount(child)
        return counts[obj.groupId]
    }

    for (let group of array)
        calculateCount(group)

    return counts

}

//

const array= [
    {
        "groupId": "group1",
        "devices": ["5","6"],
        "children": [
            {
                "groupId": "group11",
                "devices": ["1","2","3","4"],
                "children": [
                    {
                        "groupId": "group111",
                        "devices": ["7","8","9","0"],
                        "children": []
                    },
                    {
                        "groupId": "group112",
                        "devices": ["7","8","9","0"],
                        "children": []
                    }
                ]
            },
            {
                "groupId": "group12",
                "devices": ["1","2","3","4"],
                "children": [
                    {
                        "groupId": "group121",
                        "devices": ["7","8","9","0"],
                        "children": []
                    }
                ]
            }
        ]
    }
]

//

console.log(getCounts(array))

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

Reduce the number of columns in JQGrid when the window is resized

I've encountered an issue with jqGrid while working on a table with numerous columns. When resizing the browser window or viewing the web app on a mobile device, I need to display only a limited number of columns in the grid table for better usability ...

Issues arise when building with Angular using `ng build`, but everything runs smoothly when using `

My Angular 5 application uses angular-cli 1.6.8 { "name": "test", "version": "0.0.0", "license": "MIT", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "karma": "ng test", "test": "jest", "test:watch": "j ...

What is the best way to retrieve the most recent entry in a Firebase real-time database?

Utilizing Firebase's real-time database, I am updating values in a chart as they change. However, my struggle lies in retrieving only the most recent value added to the database. While browsing through limitToLast and 'child_added' do not w ...

Optimizing performance by leveraging componentDidMount while navigating between various renderings of a React component

As per the react documentation, it is recommended to use componentDidMount for AJAX calls when a component is brought into view. However, when switching between two instances of the same component with different props, componentDidMount is only triggered f ...

The Ionic Keyboard close event does not trigger

I am attempting to automatically hide the keyboard when the user scrolls within the app. Here is my code snippet: .html <ion-content class="maincontent" (ionScrollStart)="scrollStart()"> <router-outlet></router-outlet> </ion-conten ...

The Nestjs ClientMqtt now has the capability to publish both pattern and data to the broker, as opposed to just sending

I am currently utilizing Nestjs for sending data to a Mqtt Broker. However, I am facing an issue where it sends both the pattern and data instead of just the data in this format: { "pattern": "test/test", "data": " ...

AngularJS - ng-repeat: Warning: Repeated items found in the repeater and are not allowed. Repeater:

I'm currently using ng-repeat to showcase a collection of items fetched from the Twitter API. However, I am encountering an issue where Angular attempts to display the empty list while the request is still being processed, resulting in the following e ...

Identifying Typescript argument types

The given code is functional, but I am looking to refactor it for better clarity using Typescript syntax if possible. class Actions { actions: string[] } type Argument = object | Actions; export class GetFilesContext implements IExecutable { execute( ...

Aligning a div next to a text field in line

After numerous attempts, I am still struggling to align the 'add' button inline with my text field. The icon needs to be positioned correctly as shown below. I have experimented with grids and various other methods, but it refuses to cooperate. ...

Differences between the scope of if statements in JavaScript and Python

I have a function in React where I am trying to achieve the following: renderPost(data) { const dateStr = new Date(data.pub_date).toLocaleString(); let img='empty'; if (data.header_image_url.url !== null) { ...

Using jQuery in Angular, you can add a div element to hidden elements by appending

So, I have a hidden div that I want to show on button click. And not only do I want to show it, but I also want to append another div to it. The show and hide functionality is working fine, but the appending part seems tricky when dealing with hidden eleme ...

The most effective method for displaying a timestamp in the user's specific timezone using Node.JS

My application logs user events and stores timestamps as dates in Mongo, which are then converted to JS Date objects with timezone information based on the server's timezone. Although I am using moment.js to format the dates, the issue arises because ...

Error: The method .map is not a valid function in this context

I've decided to build a small To-Do app in order to enhance my knowledge of ReactJS and React Hooks. However, I'm facing an issue with the list.map() function that I'm using. The error message keeps saying that it's not a function, but ...

Display corresponding JSON images of items within an *ngFor loop in Angular

For my latest project, I am using Angular for the front-end and Laravel for the back-end. The issue I'm facing is with displaying images in Angular that are stored in Laravel storage. The image URLs are stored in the database in JSON format like this: ...

Embedding the Angular Material date picker when the page loads using an HTML tag

Currently, I am in need of a solution where the material datepicker (the datepicker itself, not just the icon) is visible on the page by default. The goal is to always have the datepicker displayed without needing to click on an icon. If anyone could pro ...

What is the best method for ensuring that a value is displayed with 2 decimal points?

When I log the code snippet below in the console: const returnedValue = Array.from( { length: 2 / 0.25 }, (_, i) => +((i + 1) * 0.25).toFixed(2), ).map((item) => ({ value: item, unit: "usd" })); The output I receive is: 1: {val ...

Incorporating PHP in JS/jQuery AJAX for creating unique odd and even conditional layouts

My PHP code includes a loop that changes the layout of elements based on whether the $count variable is odd or even. For odd counts, an image appears on the left and text on the right. For even counts, it's the other way around. To load content dynam ...

Unable to implement client-side functionalities in Angular 17 with server-side rendering

view image description hereview image description here Is there a way to make my component run on the client side, similar to "use client" in Next.js? This is my first time working with server-side rendering in Angular, and everything works fine when it&a ...

Preserving selected items in ag-grid when refreshing data sources

Just to clarify, this code snippet pertains to Angular 7 Interestingly, there is not much information available on this specific issue. I have a solution that is "working," but there is a minor issue with it. Essentially, I am calling an endpoint at regul ...

Is there a way to simplify my code and improve readability without sacrificing performance?

After completing the development of an explosive hoverboard model, it is now live on my website: . However, the code I've written seems to be quite messy and I'm struggling to optimize it without compromising performance. Is there a way to effici ...