Recursive function to filter through an array and search for parent elements

I have an array structured like this:

[
    {"id":"one","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "children":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "children":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ]

I am looking to filter this array in order to extract only the name of objects where the select field is set to true.

The desired output should be an array containing the names of these selected objects:

[student, school, school]

I attempted to achieve this using lodash:

_.filter(array, {selected: true}).map(function (division) {
            return array.name;
        });

However, this method seems to only return the root objects and not those inside the children property.

Answer №1

To determine if the desired property selected is set to true, you can iterate over the data structure and check each element, pushing it to the result array if the condition is met. If there are children elements, the iteration will continue into those as well.

This process can be achieved using Array#forEach.

// JavaScript code snippet
var data = [
  { "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }]
}
],
result = [];

data.forEach(function iter(o) {
o.selected && result.push(o.name);
(o.children || []).forEach(iter);
});

console.log(result);

A similar approach can be taken with lodash by using _.forEach.

// JavaScript code snippet using lodash
var data = [
  { "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }]
}],
result = [];

_.forEach(data, function iter(o) {
o.selected && result.push(o.name);
_.forEach(o.children, iter);
});
  
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

An alternative method using Array#reduce.

// JavaScript code snippet using reduce method
var data = [
  { "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }]
}],
result = data.reduce(function iter(r, o) {
o.selected && r.push(o.name);
return (o.children || []).reduce(iter, r);
}, []);

console.log(result);

Lastly, a version utilizing lodash's _.reduce.

// JavaScript code snippet using lodash reduce method
var data = [
  { "id": "one", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "two", "name": "school", "selected": false, "children": [{ "id": "1", "name": "school", "selected": true }, { "id": "3", "name": "teacher", "selected": false }] },
  { "name": "three", "name": "school", "selected": true, "children": [{ "id": "1", "name": "school", "selected": false }, { "id": "2", "name": "student", "selected": false }]
}],
result = _.reduce(data, function iter(r, o) {
o.selected && r.push(o.name);
return _.reduce(o.children, iter, r);
}, []);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Answer №2

array
   .reduce((a, i) => [...a, i, ...i.childs], [])//flatten array
   .filter(i => i.selected)//filter with selected===true
   .map(i => i.name));//map to name

console.log([{
  "id": "one",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "two",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "three",
  "name": "school",
  "selected": true,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": false
  }]
}].reduce((a, i) => [...a, i, ...i.childs], []).filter(i => i.selected).map(i => i.name));

Answer №3

Consider implementing this functional programming approach using ES6:

function selectItems(array) {
    return (array || []).reduce((acc, obj) => 
        (obj.selected ? acc.concat(obj.name) : acc).concat(selectItems(obj.childs)), []);
}


function selectItems(array) {
    return (array || []).reduce((acc, obj) => 
        (obj.selected ? acc.concat(obj.name) : acc).concat(selectItems(obj.childs)), []);
}
// Example data
var array = [
    {"id":"one","name":"school", "selected": false, "childs":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"two","name":"school", "selected": false, "childs":[
      {"id":"1","name":"school", "selected": true},
      {"id":"3","name":"teacher", "selected": false}
      ]},
      {"name":"three","name":"school", "selected": true, "childs":[
      {"id":"1","name":"school", "selected": false},
      {"id":"2","name":"student", "selected": false}
      ]}
  ];
// Get selected items
var result = selectItems(array);
// Display output
console.log(result);

Answer №4

You may utilize Array.prototype.map() and Array.prototype.filter()

var arr = [{
  "id": "one",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "two",
  "name": "school",
  "selected": false,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": true
  }, {
    "id": "3",
    "name": "teacher",
    "selected": false
  }]
}, {
  "name": "three",
  "name": "school",
  "selected": true,
  "childs": [{
    "id": "1",
    "name": "school",
    "selected": false
  }, {
    "id": "2",
    "name": "student",
    "selected": false
  }]
}];

var res = arr.map(el =>
  (el.selected && el || el.childs.filter(child =>
    child.selected
  )[0]).name
);

console.log(res);

Answer №5

When considering building a script, it's important to take into account the complexity involved. This particular script utilizes a nested linear algorithm, which means every element in the array must be visited to create a new data structure containing the "selected" elements. As the size of the array grows, this process can become quite slow. Here is an alternative approach you may want to consider:

Rather than creating a new array for selected elements, you could modify the method responsible for toggling the "selected" property to copy the selected object into a separate array called "selectedElements."

If you are adamant about obtaining unique results and need to follow through with the initial request, you can refer to the following code snippet:

var data = [
  {"id":"one","name":"school", "selected": false, "childs":[
    {"id":"1","name":"school", "selected": false},
    {"id":"2","name":"student", "selected": true},
    {"id":"3","name":"teacher", "selected": false}
  ]},
  {"name":"two","name":"school", "selected": false, "childs":[
    {"id":"1","name":"school", "selected": true},
    {"id":"3","name":"teacher", "selected": false}
  ]},
  {"name":"three","name":"school", "selected": true, "childs":[
    {"id":"1","name":"school", "selected": false},
    {"id":"2","name":"student", "selected": false}
  ]}
],
    selectedElements = [];

data.map(function(row, i){
  if (row.selected) {
    if (selectedElements.indexOf(row.name) == - 1)
      selectedElements.push(row.name);
  }
  else{
    row.childs.map(function(childRow, ii) {
      if (childRow.selected) {
        if (selectedElements.indexOf(childRow.name) == - 1)
          selectedElements.push(childRow.name);
        }
    })
  }
});

console.log(selectedElements);

Answer №6

Make sure to include the child elements when utilizing lodash's _.filter method.

updatedArray = _.flatten(array.map(item => [item].concat(item.children)))

This way, you can access and filter based on the children property.

Answer №7

An elegant use of arrow functions in a classic recursive solution

let finalResult = [];
let searchRecursive = arr => {
  if (Array.isArray(arr)) {
    arr.forEach(element => {
      if (element.selected === true) finalResult.push(element.name);
      if (Array.isArray(element.childs)) searchRecursive(element.childs);
    });
  }
}
searchRecursive(data);
console.log(finalResult);

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

JQuery: The .not() function does not effectively filter out items from the collection

I want to iterate through multiple span elements and extract the text from them. However, I need to skip any text that is within elements with a specific class. Here's an example: <html> <head> <script src="http://code.jquer ...

Tips for sorting through objects in the R programming language

As I navigate through my journey of learning R, I come across a seemingly simple task that tends to become unnecessarily complex. Currently, I am working on creating a basic line chart and need to filter out specific values in the data before proceeding. ...

Refreshing the Parent Component in a React Application

I'm currently delving into the world of React and TypeScript, exploring how to create a login form. Once I verify the user's details and set a cookie, I aim to refresh the parent component. This is my index.tsx (condensed version): import React ...

Error: Call stack limit reached while passing JSON data using Node.js

I am utilizing the ajax-request module to send Json data using a post request in my Node.js application. Below is the relevant code snippet: logMessage : function(url, message, next) { var d1 = message["sender"]; var d2 = { id: message[sender"]["id"], ...

Updating the columns in a row by clicking the refresh button with ajax in a JSP file

Hey there! I have a table on my JSP page with refresh buttons at the row level. When I click the refresh button, it should check the database and update those two columns with new values. Below is the code snippet for my JSP page: <script src="js/jque ...

leveraging dependency injection to retrieve a function in JavaScript

I'm exploring a way to obtain a function in JavaScript without executing it, but still defining the parameters. My current project involves creating a basic version of Angular's dependency injection system using Node.js. The inject() method is us ...

Unable to employ Datastore emulator on Nodejs app

Trying to integrate the datastore emulator with my nodejs application has been a challenge. Initially, I followed the guidelines provided here. Within my node application, I set up the following: var config = { projectId : "scio1-ts-datastore" } ...

Utilizing R to import files into an array

I have a collection of CSV files stored in the same folder. Each file consists of a table with 200 rows and columns. I am able to load and display each file separately as a matrix. I can also use the dir function to list all the files in the folder. Howeve ...

Adjust image size according to the browser's window resize using JQuery

I am trying to make an image resize based on the browser size changes using JQuery. My goal is for the image to scale without losing its aspect ratio or getting cropped. I have incorporated Bootstrap in my HTML structure: <div class="container-fluid" ...

Having difficulty with the useState hook in a material ui functional component that integrates with Firebase

Currently, I am endeavoring to create a sign-up form utilizing a Material UI functional component. Within this form, I am aiming to trigger a signup event by using the "onClick" attribute attached to the sign-up button. My approach involves passing the ema ...

Receiving a NoSessionIdError issue when using Webdriver.io

Currently, I am in the process of setting up and configuring webdriver.io and Jasmine. As per the guidelines provided, my script is located at test/specs/first/test2.js (as per the configuration) and includes the following: var webdriverio = require(&apo ...

How can NodeJS implement ThreadLocal variable functionality without relying on req and res.locals?

In a specific situation, I am required to handle business logic and logging for each request separately. This means that the data stored should not overlap with data from other requests. Using res.locals or req objects is not an option in this case becaus ...

Embrace AngularJS: Employ the ".then" method and retrieve the response

In order to send a http request and receive the response of this request, I am trying to implement a mechanism where if the data is successfully saved, I can retrieve database information, and if it fails to save, I can track errors. To achieve this, I pla ...

Having trouble with the JavaScript DOM rewrite for aligning text?

function modifyTextAlignment(){ document.getElementById("th1").style.textAlign = "right"; } #th1{ text-align:left; } <table> <tr><center><th colspan="2" id="th1">List of Important Emergency Contacts</th><center></tr& ...

The Togglesclass feature isn't functioning properly on my end

I successfully added the code to check for a cookie on my domain. if (document.cookie.indexOf("temp") >= 0) { $(".hideme").toggleClass("hide"); } else { alert("Hey, looks like you don't have a cookie set!"); } Here is the HTML section: < ...

Mouse click not functioning as anticipated

<ul> <li> <a href='javascript:;' class='close'>close</a> <a>openId</a> </li> </ul> My goal is to delete the li element when the close link (a.close) is clicked. The li elements are genera ...

What could be the reason for the sender message to only display once the recipient sends a message? (socketio) (nodejs) (reactjs)

Currently, I am working on developing a real-time chat application using Node.js, React, and Socket.io. The chat functionality is operational in theory, but there seems to be an issue where the sender's message only appears on the recipient's scr ...

Navigate to a specific section of the page by scrolling when linked to an id

Just getting started with web development and using Bootstrap to build this site. I'm working on a single-page site where the top navbar directs users to specific IDs. The issue I'm facing is that I want the page to scroll to the ID when clicked ...

Setting the starting value of `x` when iterating through `object` using `for(x in object)` loops

Here is a code sample with an array of cars: <html> <body> <script type="text/javascript"> var mycars = new Array(); mycars[0] = "Saab"; mycars[1] = "Volvo"; mycars[2] = "BMW"; ...

Unable to get Express router post function to properly function

Issue: var express = require('express'); var router = express.Router(); Route.js: Setting up Post route router.route('/signup') .post(function (req, res) { console.log('post signup called', req.body); re ...