Skip to content
Advertisement

Build nodes like array from flat array

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);
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement