Как сгруппировать значения из массива объектов по одинаковым значениям с помощью javascript?

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня есть массив объектов следующим образом

 [
0: {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, …}
1: {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, …}
2: {department_ID: 1, department_Name: "HR amp; Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, …}
   ...
]
  

Чего я хочу добиться, так это группировать значения в массиве по порядку одинаковые department_ID > одинаковые section_ID и, наконец, данные сотрудника, подобные этому

 [
  {
    department_ID: 6,
    department_Name: "Management",
    children: [
      {
        section_ID: 12,
        section_Name: "General Management",
        children: [
          {
            employee_ID: 1,
            employee_Name: "",
          },
          {
            employee_ID: 2,
            employee_Name: "",
          },
        ],
      },
    ],
  },
  {
    department_ID: 1,
    department_Name: "HR amp; Admin",
    children: [
      {
        section_ID: 20,
        section_Name: "HR and Admin",
        children: [
          {
            employee_ID: 90,
            employee_Name: "",
          },
        ],
      },
    ],
  },
];

  

Я пробовал

 function getUnique() {
  var hashObject = {};
  let obj = {};

  treeviewApiValues.forEach(function (elem) {
    var key = elem.department_ID;
    if (hashObject[key]) {
      hashObject[key] = {
        id: elem.department_ID,
        name: elem.department_Name,
        children: checkSectionID(elem),
      };
    } else {
      hashObject[key] = {
        id: elem.department_ID,
        name: elem.department_Name,
        children: checkSectionID(elem),
      };
    }
  });

  function checkSectionID(elem) {
    const key = elem.department_ID;

    if (obj[key]) {
      obj[key].push({
        id: elem.section_ID,
        name: elem.section_Name,
      });
    } else {
      obj[key] = [
        {
          id: elem.section_ID,
          name: elem.section_Name,
        },
      ];
    }

    var desiredArray2 = Object.values(obj);

    return desiredArray2;
  }

  var desiredArray = Object.values(hashObject);
}
  

Это грязная функция, но я получаю

 [
0: {department_ID: 1, department_Name: "HR amp; Admin", children: Array(7)}
1: {department_ID: 2, department_Name: "ELV Systems Installation amp; Service", children: Array(7)}
]
  

Дочерний массив — это что-то неправильное, и у него нет массива с одинаковым идентификатором department_ID, и мне также нужно получить данные сотрудника в том же section_ID.
Если бы кто-нибудь мог мне помочь, я был бы очень признателен.

Полный код можно найти здесь https://codesandbox.io/s/gracious-voice-bbmsy?file=/src/App.js

Ответ №1:

Вы могли бы использовать вложенный подход с массивом для уровней группировки.

Это решение удаляет нежелательные свойства объекта и помещает конечный объект в самый вложенный дочерний массив.

Это решение работает для произвольного количества уровней.

 const
    data = [{ department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1 }, { department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2 }, { department_ID: 1, department_Name: "HR amp; Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90 }],
    groups = [['department_ID', 'department_Name'], ['section_ID', 'section_Name']],
    result = data.reduce((r, o) => {
        groups
            .reduce((group, keys) => {
                let temp = group.find(q => q[keys[0]] === o[keys[0]]);
                if (!temp) group.push(temp = { ...Object.fromEntries(keys.map(k => [k, o[k]])), children: [] });
                keys.forEach(k => ({ [k]: _, ...o} = o));
                return temp.children;
            }, r)
            .push(o);
        return r;
    }, []);

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

Комментарии:

1. Это именно то, что мне было нужно! Большое спасибо. Однако, когда я тестирую, _ отображается undefined. Я думаю, вы забыли добавить keys.forEach((k, _) => ..) , спасибо в любом случае

2. нет, потому _ что это заполнитель для именованного свойства, которое больше не нужно.

Ответ №2:

Может быть, это решит вашу задачу

 let list = [
    {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, …},
    {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, …},
    {department_ID: 1, department_Name: "HR amp; Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, …}
    ...
];

let vals = [];
list.map(v=>{
    vals[v.department_ID] || (vals[v.department_ID] = {
        department_ID: v.department_ID,
        department_Name: v.department_Name,
        children: []
    });

    vals[v.department_ID].children[v.section_ID] || 
    (vals[v.department_ID].children[v.section_ID] = {
        section_ID: v.section_ID,
        section_Name: v.section_Name,
        children: []
    });

    vals[v.department_ID].children[v.section_ID].children.push({
        employee_ID: v.employee_ID,
        employee_Name: v.employee_Name
    });

});

vals = vals.filter(e=>!!e);
let result = vals.map(e=>{
    e.children = e.children.filter(v=>!!v);
    return e;
});
  

Ответ №3:

Вы можете использовать reduce() и find() следующим образом:

 const arr = [
  {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 1, employee_name: 'john'},
  {department_ID: 6, department_Name: "Management", section_ID: 12, section_Name: "General Management", employee_ID: 2, employee_name: 'avi'},
  {department_ID: 1, department_Name: "HR amp; Admin", section_ID: 20, section_Name: "HR and Admin", employee_ID: 90, employee_name: 'jennifer'}
]

const res = arr.reduce((acc, curr) => {
  const obj = acc.find(item => item.department_ID === curr.department_ID amp;amp; item?.children[0]?.section_ID === curr.section_ID);
  if(obj) {
    obj.children[0].children.push({ employee_ID: curr.employee_ID, employee_name: curr.employee_name});
  } else {
    acc.push({
      department_ID: curr.department_ID,
      department_Name: curr.department_Name,
      children: [
        {
          section_ID: curr.section_ID,
          section_Name: curr.section_Name,
          children: [{
            employee_ID: curr.employee_ID,
            employee_name: curr.employee_name
          }]
        }
      ]
    })
  }

  return acc;
}, []);

console.log(res);