Как преобразовать одну структуру данных в другую
Есть следующая структура данных
const persons = [
{
id: 1,
fio: 'Иванов И.И',
workPlaces: [
{
id: 222,
name: 'Рога и копыта',
},
{
id: 12,
name: 'крутая контора',
},
],
},
{
id: 2,
fio: 'Сидоров Е.Е',
workPlaces: [
{
id: 222,
name: 'Рога и копыта',
},
{
id: 333,
name: 'Другое место',
},
],
},
{
id: 3,
fio: 'Козлов А.А',
workPlaces: [
{
id: 333,
name: 'Другое место',
},
],
},
]
Как мне из этих данны получить следующий набор данных:
const workPlaces = [
{
id: 222,
name: 'Рога и копыта',
members: [
{
id: 1,
fio: 'Иванов И.И',
},
{
id: 2,
fio: 'Сидоров Е.Е',
},
],
},
{
id: 333,
name: 'Другое место',
members: [
{
id: 2,
fio: 'Сидоров Е.Е',
},
{
id: 3,
fio: 'Козлов А.А',
},
],
},
{
id: 12,
name: 'крутая контора',
members: [
{
id: 1,
fio: 'Иванов И.И',
},
],
},
]
Я пытался что то такое изобразить
const userData = []
persons.forEach((person) => {
person.workPlaces.forEach((place) => {
const membersArr = []
if (person.workPlaces.includes(place)) {
membersArr.push(person)
}
userData.push({
clinicId: place.id,
doctors: membersArr,
})
})
})
Но так получается плоская структура, потому что я массив пересоздаю каждый раз, но я просто не могу додуматься, как мне вложить в него данные корректно, если у врача такая клиника уже есть
Ответы (2 шт):
function getWorkPlaces(persons) {
return persons.reduce((workPlaces, person) => {
person.workPlaces.forEach((workPlace) => {
let place = workPlaces.find((wp) => workPlace.id === wp.id);
if (!place) {
place = { ...workPlace};
place.members = [];
workPlaces.push(place);
}
const per = { ...person};
delete per.workPlaces;
place.members.push(per);
});
return workPlaces;
}, []);
}
const persons = [{
id: 1,
fio: 'Иванов И.И',
workPlaces: [{
id: 222,
name: 'Рога и копыта',
},
{
id: 12,
name: 'крутая контора',
},
],
},
{
id: 2,
fio: 'Сидоров Е.Е',
workPlaces: [{
id: 222,
name: 'Рога и копыта',
},
{
id: 333,
name: 'Другое место',
},
],
},
{
id: 3,
fio: 'Козлов А.А',
workPlaces: [{
id: 333,
name: 'Другое место',
}, ],
},
];
console.log(getWorkPlaces(persons));
Мой алгоритм основан на том, что у двух рабочих мест не может быть одинакового id, а если это не так то всегда вместо простого id сможете использовать уникальный ключ для рабочего места. И не надо постоянно бегать по массиву и что-то искать - это очень долго будет работать на больших размерах. Всегда старайтесь придумывать алгоритмы, где не надо бегать по массиву больше одного раза. В данном случае достаточно использовать new Map() в котором элемент ищется со сложностью O(1). Вы точно так же можете вместо new Map() использовать обычный объект, при желании. Вот вам простой, понятный и быстрый алгоритм:
const persons = [{
id: 1,
fio: 'Иванов И.И',
workPlaces: [{
id: 222,
name: 'Рога и копыта',
},
{
id: 12,
name: 'крутая контора',
},
],
},
{
id: 2,
fio: 'Сидоров Е.Е',
workPlaces: [{
id: 222,
name: 'Рога и копыта',
},
{
id: 333,
name: 'Другое место',
},
],
},
{
id: 3,
fio: 'Козлов А.А',
workPlaces: [{
id: 333,
name: 'Другое место',
}],
},
]
const getPersonsWorkPlaces = (persons) => {
const workPlacesMap = new Map();
persons.forEach(person => {
const personData = {
id: person.id,
fio: person.fio
};
person.workPlaces.forEach(workPlace => {
if (workPlacesMap.has(workPlace.id)) {
workPlacesMap.get(workPlace.id).members.push(personData);
return;
}
workPlacesMap.set(workPlace.id, {...workPlace, members: [personData]});
})
})
return [...workPlacesMap.values()];
}
const workPlaces = getPersonsWorkPlaces(persons);
console.log(workPlaces);