Reputation: 527
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!
Upvotes: 1
Views: 172
Reputation: 31
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];
}
Upvotes: 1
Reputation: 50807
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.
Upvotes: 2
Reputation: 10128
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))
Upvotes: 0
Reputation: 386680
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; }
Upvotes: 2