1

I need to create a recursive function counting objects nested in the array where the selected attribute is true.

var data = [{"id":1,"code":"1","selected":false,"children":[{"id":4,"code":"1.01","selected":false,"children":[{"id":5,"code":"1.01.001","selected":true,"children":[]},{"id":6,"code":"1.01.002","selected":false,"children":[]},{"id":20,"code":"1.01.003","selected":true,"children":[]}]}]},{"id":2,"code":"2","selected":false,"children":[{"id":7,"code":"2.01","selected":false,"children":[{"id":9,"code":"2.01.001","selected":true,"children":[]},{"id":21,"code":"2.01.002","selected":true,"children":[]},{"id":22,"code":"2.01.003","selected":false,"children":[]}]}]},{"id":3,"code":"3","selected":false,"children":[{"id":8,"code":"3.01","selected":false,"children":[{"id":10,"code":"3.01.01","name":"Sementes","selected":false,"children":[{"id":11,"code":"3.01.01.001","selected":true,"children":[]},{"id":23,"code":"3.01.01.002","selected":false,"children":[]},{"id":24,"code":"3.01.01.003","selected":true,"children":[]}]},{"id":25,"code":"3.01.02","selected":false,"children":[{"id":27,"code":"3.01.02.001","selected":true,"children":[]},{"id":28,"code":"3.01.02.002","selected":false,"children":[]},{"id":29,"code":"3.01.02.003","selected":false,"children":[]}]},{"id":26,"code":"3.01.03","selected":false,"children":[{"id":30,"code":"3.01.03.001","selected":true,"children":[]},{"id":31,"code":"3.01.03.002","selected":true,"children":[]},{"id":32,"code":"3.01.03.003","selected":true,"children":[]},{"id":35,"code":"3.01.03.004","selected":false,"children":[]},{"id":34,"code":"3.01.03.005","selected":false,"children":[]}]}]}]}];


const countSelectedChildren = (arr) => {

return arr;
}

console.log(countSelectedChildren(data))

Expected response:

{
    "id": 3,
    "code": "3",
    "selected": false,
    "selectedChildren": 6,
    "children": [
      {
        "id": 8,
        "code": "3.01",
        "selected": false,
        "selectedChildren": 6,
        "children": [
          {
            "id": 10,
            "code": "3.01.01",
            "name": "Sementes",
            "selected": false,
            "selectedChildren": 2,
            "children": [
              {
                "id": 11,
                "code": "3.01.01.001",
                "selected": true,
                "children": []
              },
              {
                "id": 23,
                "code": "3.01.01.002",
                "selected": false,
                "children": []
              },
              {
                "id": 24,
                "code": "3.01.01.003",
                "selected": true,
                "children": []
              }
            ]
          },
          {
            "id": 25,
            "code": "3.01.02",
            "selected": false,
            "selectedChildren": 1,
            "children": [
              {
                "id": 27,
                "code": "3.01.02.001",
                "selected": true,
                "children": []
              },
              {
                "id": 28,
                "code": "3.01.02.002",
                "selected": false,
                "children": []
              },
              {
                "id": 29,
                "code": "3.01.02.003",
                "selected": false,
                "children": []
              }
            ]
          },
          {
            "id": 26,
            "code": "3.01.03",
            "selected": false,
            "selectedChildren": 3,
            "children": [
              {
                "id": 30,
                "code": "3.01.03.001",
                "selected": true,
                "children": []
              },
              {
                "id": 31,
                "code": "3.01.03.002",
                "selected": true,
                "children": []
              },
              {
                "id": 32,
                "code": "3.01.03.003",
                "selected": true,
                "children": []
              },
              {
                "id": 35,
                "code": "3.01.03.004",
                "selected": false,
                "children": []
              },
              {
                "id": 34,
                "code": "3.01.03.005",
                "selected": false,
                "children": []
              }
            ]
          }
        ]
      }
    ]
  }

Can you help me to create this recursive function?

const countSelectedChildren = (arr) => {

return arr;
}

Thanks for your help!

3
  • You need to write a recursive function to process the nested arrays. Commented Feb 1, 2023 at 18:04
  • Can you write this recursive function? Commented Feb 1, 2023 at 18:06
  • 4
    I can, but I won't. What's preventing you from writing it, it's not very complicated? Commented Feb 1, 2023 at 18:09

4 Answers 4

2

You could take a recursive function for an array and return an object with a counting property and a children array.

const
    addSelected = array => {
        let selectedChildren = 0;
        const
            children = array.map(({ children, ...o }) => {
                if (o.selected) selectedChildren++;
                const temp = addSelected(children);
                selectedChildren += temp.selectedChildren || 0;
                return { ...o, ...temp };
            });

        return children.length
            ? { selectedChildren, children }
            : { children };
    },
    data = [{ id: 1, code: "1", selected: false, children: [{ id: 4, code: "1.01", selected: false, children: [{ id: 5, code: "1.01.001", selected: true, children: [] }, { id: 6, code: "1.01.002", selected: false, children: [] }, { id: 20, code: "1.01.003", selected: true, children: [] }] }] }, { id: 2, code: "2", selected: false, children: [{ id: 7, code: "2.01", selected: false, children: [{ id: 9, code: "2.01.001", selected: true, children: [] }, { id: 21, code: "2.01.002", selected: true, children: [] }, { id: 22, code: "2.01.003", selected: false, children: [] }] }] }, { id: 3, code: "3", selected: false, children: [{ id: 8, code: "3.01", selected: false, children: [{ id: 10, code: "3.01.01", name: "Sementes", selected: false, children: [{ id: 11, code: "3.01.01.001", selected: true, children: [] }, { id: 23, code: "3.01.01.002", selected: false, children: [] }, { id: 24, code: "3.01.01.003", selected: true, children: [] }] }, { id: 25, code: "3.01.02", selected: false, children: [{ id: 27, code: "3.01.02.001", selected: true, children: [] }, { id: 28, code: "3.01.02.002", selected: false, children: [] }, { id: 29, code: "3.01.02.003", selected: false, children: [] }] }, { id: 26, code: "3.01.03", selected: false, children: [{ id: 30, code: "3.01.03.001", selected: true, children: [] }, { id: 31, code: "3.01.03.002", selected: true, children: [] }, { id: 32, code: "3.01.03.003", selected: true, children: [] }, { id: 35, code: "3.01.03.004", selected: false, children: [] }, { id: 34, code: "3.01.03.005", selected: false, children: [] }] }] }] }],
    result = addSelected(data).children;

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

Sign up to request clarification or add additional context in comments.

Comments

2

Here's a fairly simple recursion to do this:

const sum = (ns) => ns .reduce ((a, b) => a + b, 0)

const countSelectedChildren = (xs) => 
  xs .map (({children = [], ...rest}, _, __, kids = countSelectedChildren (children)) => ({
    ...rest,
    ...(children .length 
       ? {selectedChildren: sum (kids .map (x => (x .selected ? 1 : 0) + (x .selectedChildren || 0)))}
       : {}
    ),
    children: kids,
  }))

const data = [{"id":1,"code":"1","selected":false,"children":[{"id":4,"code":"1.01","selected":false,"children":[{"id":5,"code":"1.01.001","selected":true,"children":[]},{"id":6,"code":"1.01.002","selected":false,"children":[]},{"id":20,"code":"1.01.003","selected":true,"children":[]}]}]},{"id":2,"code":"2","selected":false,"children":[{"id":7,"code":"2.01","selected":false,"children":[{"id":9,"code":"2.01.001","selected":true,"children":[]},{"id":21,"code":"2.01.002","selected":true,"children":[]},{"id":22,"code":"2.01.003","selected":false,"children":[]}]}]},{"id":3,"code":"3","selected":false,"children":[{"id":8,"code":"3.01","selected":false,"children":[{"id":10,"code":"3.01.01","name":"Sementes","selected":false,"children":[{"id":11,"code":"3.01.01.001","selected":true,"children":[]},{"id":23,"code":"3.01.01.002","selected":false,"children":[]},{"id":24,"code":"3.01.01.003","selected":true,"children":[]}]},{"id":25,"code":"3.01.02","selected":false,"children":[{"id":27,"code":"3.01.02.001","selected":true,"children":[]},{"id":28,"code":"3.01.02.002","selected":false,"children":[]},{"id":29,"code":"3.01.02.003","selected":false,"children":[]}]},{"id":26,"code":"3.01.03","selected":false,"children":[{"id":30,"code":"3.01.03.001","selected":true,"children":[]},{"id":31,"code":"3.01.03.002","selected":true,"children":[]},{"id":32,"code":"3.01.03.003","selected":true,"children":[]},{"id":35,"code":"3.01.03.004","selected":false,"children":[]},{"id":34,"code":"3.01.03.005","selected":false,"children":[]}]}]}]}];

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

For each element in the input array recur first on any children, then to calculate the selectedChildren for our current node we sum up the results from each of our children, adding one for each if it's selected. Then we simply put back together a new object with selectedChildren included if we have actual children, with children the result of our recursion, and with the rest of the properties from our element.

While we could inline the one call to the sum helper function, it's something we're likely to want fairly often, so it's cleaner to keep it separate.

Comments

1

const countSelectedChildren = (data) => {
   let length = 0;
   for (item of data) {
      item.selected && (length++)
      let child_length = countSelectedChildren(item.children || [])[1];
      length += child_length;
      item.selectedChildren = child_length;
   }
   return [data, length];
}

1 Comment

Note the expected output. The title is misleading. The OP want not just to count them but to return a tree with nodes that have a new selectedChildren property.
0

I would approach it like this

    const countSelectedChildren = (inArr) => {
        
        const outArr = [];
        
        inArr.forEach(row => {
        
          //  simply count all chilren with selected=true
          row.SelectedChildren = row.children.filter(row => row.selected).length;
        
          //  if there are children, call this function on them
          if (row.children.length) {
             row.children = countSelectedChildren(row.children);
          }
          
          outArr.push(row);
        });
        
        return outArr;
        
    }

const data = [
  {
"id": 1,
"code": "1",
"selected": false,
"children": [
  {
    "id": 4,
    "code": "1.01",
    "selected": false,
    "children": [
      {
        "id": 5,
        "code": "1.01.001",
        "selected": true,
        "children": []
      },
      {
        "id": 6,
        "code": "1.01.002",
        "selected": false,
        "children": []
      },
      {
        "id": 20,
        "code": "1.01.003",
        "selected": true,
        "children": []
      }
    ]
  }
]
  },
  {
"id": 2,
"code": "2",
"selected": false,
"children": [
  {
    "id": 7,
    "code": "2.01",
    "selected": false,
    "children": [
      {
        "id": 9,
        "code": "2.01.001",
        "selected": true,
        "children": []
      },
      {
        "id": 21,
        "code": "2.01.002",
        "selected": true,
        "children": []
      },
      {
        "id": 22,
        "code": "2.01.003",
        "selected": false,
        "children": []
      }
    ]
  }
]
  },
  {
"id": 3,
"code": "3",
"selected": false,
"children": [
  {
    "id": 8,
    "code": "3.01",
    "selected": false,
    "children": [
      {
        "id": 10,
        "code": "3.01.01",
        "name": "Sementes",
        "selected": false,
        "children": [
          {
            "id": 11,
            "code": "3.01.01.001",
            "selected": true,
            "children": []
          },
          {
            "id": 23,
            "code": "3.01.01.002",
            "selected": false,
            "children": []
          },
          {
            "id": 24,
            "code": "3.01.01.003",
            "selected": true,
            "children": []
          }
        ]
      },
      {
        "id": 25,
        "code": "3.01.02",
        "selected": false,
        "children": [
          {
            "id": 27,
            "code": "3.01.02.001",
            "selected": true,
            "children": []
          },
          {
            "id": 28,
            "code": "3.01.02.002",
            "selected": false,
            "children": []
          },
          {
            "id": 29,
            "code": "3.01.02.003",
            "selected": false,
            "children": []
          }
        ]
      },
      {
        "id": 26,
        "code": "3.01.03",
        "selected": false,
        "children": [
          {
            "id": 30,
            "code": "3.01.03.001",
            "selected": true,
            "children": []
          },
          {
            "id": 31,
            "code": "3.01.03.002",
            "selected": true,
            "children": []
          },
          {
            "id": 32,
            "code": "3.01.03.003",
            "selected": true,
            "children": []
          },
          {
            "id": 35,
            "code": "3.01.03.004",
            "selected": false,
            "children": []
          },
          {
            "id": 34,
            "code": "3.01.03.005",
            "selected": false,
            "children": []
          }
        ]
      }
    ]
  }
]
  }
];


const countSelectedChildren = (inArr) => {
    
    const outArr = [];
    
    inArr.forEach(row => {
    
      //  simply count all chilren with selected=true
      row.SelectedChildren = row.children.filter(row => row.selected).length;
    
      //  if there are children, call this function on them
      if (row.children.length) {
         row.children = countSelectedChildren(row.children);
      }
      
      outArr.push(row);
    });
    
    return outArr;
    
}

console.log(countSelectedChildren(data))

1 Comment

I think you need to account for the totals you're gathering for the children in the parent as well. For instance id: 3 should have a selectedChildren length of 6.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.