Как преобразовать структуру данных из массива объектов в многомерный объект?

Как можно преобразовать следующую структуру данных: 

```javascript
let events = [
  { date: '2019-12', event: 'name1' },
  { date: '2019-12', event: 'name2' },
  { date: '2019-11', event: 'name3' },
  { date: '2019-11', event: 'name4' },
  { date: '2020-10', event: 'name5' },
  { date: '2020-10', event: 'name6' },
  { date: '2020-11', event: 'name5' },
  { date: '2020-11', event: 'name6' },
  { date: '2020-12', event: 'name7' },
  { date: '2020-12', event: 'name8' },
  { date: '2020-12', event: 'name9' }
];
```

В следующую структуру:

```javascript
{
  2019: {
    11: [массив событий],
    12: [массив событий],
  },
  2020: {
    10: [массив событий],
    11: [массив событий],
    12: [массив событий],
  }
}
```

Я пробовал подход с использованием `reduce`, но не получил правильного результата. Вот что у меня есть: 

```javascript
let res = events.reduce((newArr, elem) => {
  let key1 = elem.date.split('-')[0];
  let key2 = elem.date.split('-')[1];
  return {
    ...newArr,
    key1: { key2: [].push(elem.event) },
  };
}, {});
console.log(res);
```

Кроме того, я пробовал использовать цикл `for`, но тоже безуспешно. Вот этот код:

```javascript
let obj = [];
for (let elem of events) {
  let key = elem.date.split('-')[0];
  let key1 = elem.date.split('-')[1];

  if (!obj.includes(key)) {
    obj.push(key);
  }

  if (!obj[key].includes(key1)) {
    obj[key].push(key1);
  }
}
console.log(obj);
```

У меня не получилось достичь нужного результата. Буду признателен за любые подсказки или решения!
  • 13 сентября 2024 г. 19:13
Ответы на вопрос 1
Вы на правильном пути с использованием `reduce`, но давайте немного доработаем ваш код. Чтобы получить желаемую структуру данных, мы можем просто аккуратно накапливать события по годам и месяцам.

Вот пример того, как это можно сделать с помощью метода `reduce`:

```javascript
let events = [
  { date: '2019-12', event: 'name1' },
  { date: '2019-12', event: 'name2' },
  { date: '2019-11', event: 'name3' },
  { date: '2019-11', event: 'name4' },
  { date: '2020-10', event: 'name5' },
  { date: '2020-10', event: 'name6' },
  { date: '2020-11', event: 'name5' },
  { date: '2020-11', event: 'name6' },
  { date: '2020-12', event: 'name7' },
  { date: '2020-12', event: 'name8' },
  { date: '2020-12', event: 'name9' }
];

let result = events.reduce((acc, { date, event }) => {
  let [year, month] = date.split('-');
  
  // Преобразуем year и month в числа
  year = Number(year);
  month = Number(month);

  // Проверяем наличие года в результирующем объекте
  if (!acc[year]) {
    acc[year] = {};
  }

  // Проверяем наличие месяца в году
  if (!acc[year][month]) {
    acc[year][month] = [];
  }

  // Добавляем событие в массив для данного месяца
  acc[year][month].push(event);

  return acc;
}, {});

console.log(result);
```

Этот код делает следующее:

1. Метод `reduce` инициализируется с пустым объектом `acc`.
2. Для каждого события мы извлекаем `year` и `month`, разбивая строку `date`.
3. Мы проверяем, существует ли уже этот `year` в результирующем объекте, и если нет, создаем новый объект для этого года.
4. Затем мы проверяем наличие `month` в этом году и создаем пустой массив, если его нет.
5. В конце мы добавляем событие в соответствующий массив.

После выполнения кода у вас будет объект, который соответствует желаемой структуре. Вы получите вывод в следующем формате:

```javascript
{
  2019: {
    11: ['name3', 'name4'],
    12: ['name1', 'name2']
  },
  2020: {
    10: ['name5', 'name6'],
    11: ['name5', 'name6'],
    12: ['name7', 'name8', 'name9']
  }
}
```
Похожие вопросы