Home > Mobile >  Group by arrays
Group by arrays

Time:11-27

Aim

Group tasks per employee/group of employees for which tasks were assigned to.

Data Context

  • Each task can be assigned to more than one employee
  • Each employee can have multiple tasks
  • Values like employee type or name are just extra data, meaning it's the employee_id that distinguishes them

Problem

Currently, I am able to group the tasks per employee, not group of employees. If a task is shared by more than one employee, it is repeated on the array, like the example tasks below (appear in 2 employees groups: for employee_id 111 and 999 if you run the last code snippet that has both the initial data and my current code).

  {
    "task_employee_id": 10001,
    "task_name": "Maintenance",
    "task_url": "www.task_url10001.com",
    "status": "incomplete"
  },
  {
    "task_employee_id": 20002,
    "task_name": "Cleaning",
    "task_url": "www.task_url20002.com",
    "status": "completed"
  },

Expected Result

I should have it like this

groupTasks:  [
  {
    "employee_id": [{999},{111}]
    "type": "ABC",
    "name": "Lorem",
    "tasks": [
      {
        "task_employee_id": 10001,
        "task_name": "Maintenance",
        "task_url": "www.task_url10001.com",
        "status": "incomplete"
      },
      {
        "task_employee_id": 20002,
        "task_name": "Cleaning",
        "task_url": "www.task_url20002.com",
        "status": "completed"
      }
    ]
  },
  {
    "employee_id": 111,
    "type": "ZHG",
    "name": "Ipsum",
    "tasks": [
      {
        "task_employee_id": 30003,
        "task_name": "Fixing",
        "task_url": "www.task_url30003.com",
        "status": "incomplete"
      }
    ]
  },
  {
    "employee_id": 999,
    "type": "ABC",
    "name": "Lorem",
    "tasks": [
      {
        "task_employee_id": 40004,
        "task_name": "Checking",
        "task_url": "www.task_url40004.com",
        "status": "complete"
      }
   ]
  ]

Sidenote: it could either be "employee_ids": [{"employee_id" :999},{"employee_id" : 111}] or "employee_id": [999,111]

Here is the code snippet with the initial data and my current code that doesn't ouput the expected result

const data = [
  {
    task_id: 10001,
    task_name: "Maintenance",
    task_url: "www.task_url10001.com",
    status: "incomplete",
    employees: [
      { employee_id: 999, type: "ABC", name: "Lorem" },
      { employee_id: 111, type: "ZHG", name: "Ipsum" }
    ]
  },
  {
    task_id: 20002,
    task_name: "Cleaning",
    task_url: "www.task_url20002.com",
    status: "completed",
    employees: [
      { employee_id: 111, type: "ZHG", name: "Ipsum" },
      { employee_id: 999, type: "ABC", name: "Lorem" }
    ]
  },
  {
    task_id: 30003,
    task_name: "Fixing",
    task_url: "www.task_url30003.com",
    status: "incomplete",
    employees: [{ employee_id: 111, type: "ZHG", name: "Ipsum" }]
  },
  {
    task_id: 40004,
    task_name: "Checking",
    task_url: "www.task_url40004.com",
    status: "complete",
    employees: [{ employee_id: 999, type: "ABC", name: "Lorem" }]
  }
];


// current approach

const groupTasks = [
  ...data
    .reduce(
      (
        groupTasksEmployees,
        {
          task_id: task_employee_id,
          task_name,
          task_url,
          status,
          employees = []
        }
      ) => {
        employees.forEach(({ employee_id, type, name }) => {
          const employees = groupTasksEmployees.get(employee_id) ?? {
            employee_id,
            type,
            name,
            tasks: []
          };
          employees.tasks.push({
            task_employee_id,
            task_name,
            task_url,
            status
          });
          groupTasksEmployees.set(employee_id, employees);
        });
        return groupTasksEmployees;
      },
      new Map()
    )
    .values()
];
console.log("groupTasks: ", groupTasks);

CodePudding user response:

A possible solution, obtained by a slight modification of your code, could be:

const data = [
    {
        task_id: 10001,
        task_name: "Maintenance",
        task_url: "www.task_url10001.com",
        status: "incomplete",
        employees: [
            { employee_id: 999, type: "ABC", name: "Lorem" },
            { employee_id: 111, type: "ZHG", name: "Ipsum" }
        ]
    },
    {
        task_id: 20002,
        task_name: "Cleaning",
        task_url: "www.task_url20002.com",
        status: "completed",
        employees: [
            { employee_id: 111, type: "ZHG", name: "Ipsum" },
            { employee_id: 999, type: "ABC", name: "Lorem" }
        ]
    },
    {
        task_id: 30003,
        task_name: "Fixing",
        task_url: "www.task_url30003.com",
        status: "incomplete",
        employees: [{ employee_id: 111, type: "ZHG", name: "Ipsum" }]
    },
    {
        task_id: 40004,
        task_name: "Checking",
        task_url: "www.task_url40004.com",
        status: "complete",
        employees: [{ employee_id: 999, type: "ABC", name: "Lorem" }]
    }
];


// current approach

const groupTasks = [
    ...data
        .reduce(
            (
                groupTasksEmployees,
                {
                    task_id: task_employee_id,
                    task_name,
                    task_url,
                    status,
                    employees = []
                }
            ) => {
                let employee_ids = employees.map(o=>o.employee_id).sort();
                const employee_ids_unique = employee_ids.join('_'),
                    type = employees[0]?.type,
                    name = employees[0]?.name;
                if(employee_ids.length === 1){
                    employee_ids = employee_ids[0];
                }
                
                const employees_g = groupTasksEmployees.get(employee_ids_unique) ?? {
                    employee_id: employee_ids,
                    type,
                    name,
                    tasks: []
                };
                employees_g.tasks.push({
                    task_employee_id,
                    task_name,
                    task_url,
                    status
                });
                groupTasksEmployees.set(employee_ids_unique, employees_g);
                return groupTasksEmployees;
            },
            new Map()
        )
        .values()
];
console.log("groupTasks: ", groupTasks);

This seems to produce your expected result, including the selection of only one name and one type in the aggregated data. It could easily be modified to include all employee names and types for each task that contains more than one employee.

CodePudding user response:

Make a key from all of the employee ids and use that to refer to the group in the reduce accumulator.

   const output = data.reduce((acc, {employees, ...rest}) => {
      const group = employees.map(e => e.employee_id).sort();
      const key = group.join('_');
      if(!acc[key]) {
        acc[key] = {
          id: group,
          tasks: []
        };
      }
      acc[key].tasks.push(rest);
      return acc;
   }, {});
   const arr = Object.values(output);
    
  • Related