Best way to extract objects from an array by filtering based on the nested property value at nth level in JavaScript

Looking for a Solution: Is there an efficient method to filter out objects from an array based on a specific property value without using recursion?

The Issue: While the recursive approach works for filtering, it struggles with performance due to a large dataset and numerous nested objects within each object.

Here is a snippet of sample data:

[{
  children: [{
    children: [{
      children: [],
      isWorking: 'yes'
    }]
  }]
}, {
  children: [],
  isWorking: 'no'
}, {
  children: [{
    children: [{
      children: [],
      isWorking: 'no'
    }]
  }]
}, {
  children: [{
    children: [],
    isWorking: 'yes'
  }]
}, ...]
  • I want to filter out the top-level objects that have a nested isWorking property set to yes.
  • The isWorking property is only present in objects without any children. i.e. children: []

While I have achieved this using recursion, I am seeking a more optimized solution to enhance performance.

This is my current working solution:

const parent = [{
  children: [{
    children: [{
      children: [],
      isWorking: 'yes'
    }]
  }]
}, {
  children: [],
  isWorking: 'no'
}, {
  children: [{
    children: [{
      children: [],
      isWorking: 'no'
    }]
  }]
}, {
  children: [{
    children: [],
    isWorking: 'yes'
  }]
}];

const isWorkingFlagArr = [];

function checkForOccupation(arr) {
  arr.forEach(obj => {
    (!obj.children.length) ? isWorkingFlagArr.push(obj.isWorking === 'yes') : checkForOccupation(obj.children)
  })
}

checkForOccupation(parent);

const res = parent.filter((obj, index) => isWorkingFlagArr[index]);

console.log(res);

Answer №1

This solution tackles the issue of stack overflow by queuing each recursive call as a new microtask.

While implementing the same algorithm as yours, this code ensures that recursive calls are executed asynchronously on separate microtasks.

Take note of the following details 👇

i. Top-level async is not supported by StackOverflow.

ii. async keyword is utilized to enable the use of await functionality.

iii. Employing an Async IIFE (Immediately Invoked Function Expression).

iv. Your original algorithm implementation.

v. Pausing the loop execution until the promise from the recursive call is resolved. This acts similar to using

.then(() => checkForOccupation(children))
, allowing for asynchronous recursive calls with fresh stacks on microtasks to prevent deep nesting issues and lack of tail-call recursion optimization in JavaScript, albeit it may come with performance consequences.

vi. Initiation of the async IIFE to start the process.

vii. Executing the outer async IIFE to work around the absence of top-level async support in StackOverflow environments.

(async () => {  // i.
  const getFlags = async (arr) => {  // ii.
      const flags = []

      await (async function checkForOccupation(arr) {  // iii.
          for(const { children, isWorking } of arr) {  // iv.
              !children.length
                  ? flags.push(isWorking === 'yes') 
                  : await checkForOccupation(children)  // v.
          }
      })(arr)  // vi.

      return flags
  }

  const data = [{
    children: [{
      children: [{
        children: [],
        isWorking: 'yes'
      }]
    }]
  }, {
    children: [],
    isWorking: 'no'
  }, {
    children: [{
      children: [{
        children: [],
        isWorking: 'no'
      }]
    }]
  }, {
    children: [{
      children: [],
      isWorking: 'yes'
    }]
  }]

  const flags = await getFlags(data)
  console.log(data.filter((_, index) => flags[index]))
})()

An alternative method would involve managing state explicitly through a stack, which can be cumbersome to implement.

Answer №2

I can't guarantee if this code will outperform yours, but I believe it's much simpler:

const checkForOccupation = (xs) => xs .flatMap (
  (x, _, __, kids = checkForOccupation (x .children || [])) => 
    x .isWorking == 'yes' || kids .length > 0  ? [{...x, children: kids}] : []
)

const data = [{children: [{children: [{children: [{children: [], isWorking: 'no'}], isWorking: 'yes'}]}]}, {children: [], isWorking: 'no'}, {children: [{children: [{children: [], isWorking: 'no'}]}]}, {children: [{children: [], isWorking: 'yes'}]}]

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

By using flatMap, we combine transformation and filtering in one step. We recursively iterate over the children array of each node, checking for a specific value in the process. If certain conditions are met, we return an object with modified properties to flatMap, otherwise, we return an empty array. The results are then flattened by flatMap.

Some concerns were raised about potential stack overflow, which should only happen with deeply nested objects. In such extreme cases, stack overflow would likely be the least of your worries.

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

Activate the following and preceding elements within the 'vue-owl-carousel' component for Vue.js

I'm facing an issue with navigating to the next or previous item in the vue-owl-carousel package while using Vue and javascript. Is there anyone who can provide assistance? Below is the code for the carousel : <carousel id="newGamesCarousel" :it ...

My Vue.js accordion menu component is experiencing issues with toggle flags, causing it to malfunction

I have been working on my test case using Vue and I recently created a component called MultiAccordion. My intention was to open each slide based on the value of the status[index] flag. However, I am encountering an issue as this component does not seem ...

Connecting Angular directive values to controller objects

I am facing an issue where the array values updated in the controller are not reflecting in the directive. The controller fetches data from a service and stores it into an array, which I then pass to the directive to create a bar graph. Below are the essen ...

A tool that enhances the visibility and readability of web languages such as HTML, PHP, and CSS

Looking to organize my own code examples, I need a way to display my code with syntax highlighting. Similar to how Symfony framework showcases it on their website: http://prntscr.com/bqrmzk. I'm wondering if there is a JavaScript framework that can a ...

Ways to monitor automatic data alterations within a Vue JS component

I have a method that updates data within the component itself, for example: Vue.component('component', { template: '#component', data: function () { return { dataToBeWatched: '' } }, methods: { chang ...

Updating JavaScript alert title in Android webview: A guide for developers

I have integrated a web view in my Android application, which contains a button. When the button is clicked, it triggers a JavaScript function that displays an alert box with the title "The page at 'file://' says". I would like to customize this ...

Breaking apart a string and mapping it to specific fields

My issue is relatively straightforward. Upon loading my page, a long string representing an address is generated. For example: 101, Dalmations Avenue, Miami, Florida, USA, 908343 With the help of jQuery, I can split the string using: var address = sel.o ...

Issue with PHP Ajax Image Upload

I am currently working on setting up an Ajax image upload feature. Unfortunately, I am encountering issues and unable to identify the root cause. <script> $(document).ready(function() { $("#uploadBTN").click(function(event) { ...

Enhance or Delete Dynamic linked select boxes in Laravel

Here is a straightforward dynamic form where you can choose a country from the first select box and it will display all the states of that country in each row. Initially, it worked fine for the first row but when I clicked on "Add More" and selected anothe ...

Adjust the color of the sidebar's list items when scrolling

How can I change the background color of left sticky sidebars li on scrolling? When scrolling through BMW, BMW's background color in the sidebar should turn green. Please refer to the code snippet provided below. The background color of the li ...

Implementing a JavaScript function to a button within an existing form in JSP - Best practices

Currently, I am working on developing multiple JSP pages and I encountered a requirement where I needed to add a function to a button within an already existing form. The challenge was that the form's submit button was configured to navigate to anothe ...

Having difficulty uploading an image to Facebook through the graph API

I have a requirement to upload a photo to Facebook using the Javascript SDK, but I am experiencing some difficulties: Firstly, FB.login(function (response) { if (response.authResponse) { va ...

What is the best way to refresh flexslider after it has been updated via AJAX?

At first, my slider is functional upon loading the page. However, after making an ajax call and receiving new slides to populate the slider, it becomes deactivated (as expected) https://i.sstatic.net/LC0yG.png Is there a method to reinitialize the flexsl ...

How to implement various middlewares in Express.js depending on the current environment using NODE_ENV?

My dilemma involves utilizing two different middlewares based on NODE_ENV: router1 for production and router2 for testing and development environments. I'm currently using the following code snippet: if( process.env.NODE_ENV === 'prod' ) { ...

JavaScript codes within HTML elements may not be functional when using an AJAX loader to transition to the next page

I'm experiencing issues with an ajax loader in Wordpress. The theme I am using has an ajax loader button that is interfering with my inline script. Despite reading over 10 articles on the problem, I haven't been able to find a solution yet. Do ...

Incorporating an HTML5 Theme with Angular 2

Is there a way to effectively set up my current Theme, which is built using bootstrap, CSS, and JS? I have included the following CSS and JS files in my theme, but I don't want to add them directly to index.html like in Angular 1. Can anyone suggest ...

Creating an effective Google Login Button in a React application

Struggling to implement a Login/Sign In Google Button on my page using react, I'm new to this framework and it's just not working as expected. Following tutorials from the internet but still facing issues. To summarize, I'm utilizing tailw ...

Angular is notifying that an unused expression was found where it was expecting an assignment or function call

Currently, I am working on creating a registration form in Angular. My goal is to verify if the User's username exists and then assign that value to the object if it is not null. loadData(data: User) { data.username && (this.registrationD ...

Struct object not found within nested array during JSON unmarshaling

Encountered an issue with unmarshalling a string back to a struct object that contains a nested array of struct objects. The problem is demonstrated in the following code snippet: The JSON string is as follows: const myStr = `{ "name": "test_session1", ...

How to retrieve and modify JSON data in Node.js using Stream with both Get and Post methods

Exploring Node.js for the first time, I'm currently tackling a project where I aim to utilize Request for streaming data from one endpoint to another. The objective is to leverage Request for extracting and posting an altered JSON body through a pipe ...