I’m trying to restructure the following javascript flat array without parent_id.
I want to have a structure for React Tree Table like example in this page: https://www.robinwieruch.de/react-tree-table/
data = [{ id: 1, activity: 'Activity 1', workplace: 'Workplace 1', machine: 'Machine 1', error: 'Error 1' number: 'Doc number 1' hours: 4, }, { id: 2, activity: 'Activity 1', workplace: 'Workplace 1', machine: 'Machine 2', error: 'Error 2' number: 'Doc number 2' hours: 3, }, { id: 3, activity: 'Activity 2', workplace: 'Workplace 2', machine: 'Machine 3', error: 'Error 3' number: 'Doc number 3' hours: 3, }, { id: 4, activity: 'Activity 2', workplace: 'Workplace 3', machine: 'Machine 4', error: 'Error 4' number: 'Doc number 4' hours: 6, }, .... ]
I want a another array that dynamically group according to this array’s keys:
groups = ['activity', 'workplace', ...]
I want to have a structure like this and pass an another array to group. Ideally a want sum the hours in each group
data = [{ name: 'Activity 2', hours: 7 nodes: [ name: 'Workplace 2', hours: 7, nodes: [{ id: 1, activity: 'Activity 1', workplace: 'Workplace 1', machine: 'Machine 1', error: 'Error 1' number: 'Doc number 1' hours: 4, }, id: 2, activity: 'Activity 1', workplace: 'Workplace 1', machine: 'Machine 2', error: 'Error 2' number: 'Doc number 2' hours: 3, }, ] ] }, { name: 'Activity 2', hours: 7 nodes: [ name: 'Workplace 2', hours: 3, nodes: [{ id: 1, activity: 'Activity 2', workplace: 'Workplace 2', machine: 'Machine 3', error: 'Error 3' number: 'Doc number 3' hours: 3, } ] ], [ name: 'Workplace 3', hours: 6, nodes: [{ id: 1, activity: 'Activity 2', workplace: 'Workplace 3', machine: 'Machine 4', error: 'Error 4' number: 'Doc number 4' hours: 6, } ] ] }]
I have already make this code:
const groupOverview = () => data .reduce((r, o) => { activatedGroup.reduce((p, key) => { let name = o[key], temp = (p.nodes = p.nodes || []).find(q => q.name === name); if (!temp) { p.nodes.push(temp = { name }); } return temp; }, r) return r; }, { nodes: [] }) .nodes;
But I don’t have sums and all informations in the last children.
Advertisement
Answer
You could use a recursive function. First create a map keyed by the data for the first key, associating a group object with nodes
and hours
properties, and then populate the nodes and sum up the hours.
Then repeat in recursion for those (smaller) node arrays. The recursion stops when there are no more keys to group by.
Here is an implementation:
function groupAndSum(data, [key, ...keys]) { if (key === undefined) return data; const groups = new Map(data.map(o => [o[key], { name: o[key], hours: 0, nodes: [] }])); for (const o of data) { const parent = groups.get(o[key]); parent.nodes.push(o); parent.hours += o.hours; } for (const o of groups.values()) o.nodes = groupAndSum(o.nodes, keys); return [...groups.values()]; } // Your example data const data = [{id: 1,activity: 'Activity 1',workplace: 'Workplace 1',machine: 'Machine 1',error: 'Error 1',number: 'Doc number 1',hours: 4,}, {id: 2,activity: 'Activity 1',workplace: 'Workplace 1',machine: 'Machine 2',error: 'Error 2',number: 'Doc number 2',hours: 3,}, {id: 3,activity: 'Activity 2',workplace: 'Workplace 2',machine: 'Machine 3',error: 'Error 3',number: 'Doc number 3',hours: 3,}, {id: 4,activity: 'Activity 2',workplace: 'Workplace 3',machine: 'Machine 4',error: 'Error 4',number: 'Doc number 4',hours: 6,}]; const result = groupAndSum(data, ["activity", "workplace"]); console.log(result);