Преобразовать массив в следующий формат

У меня есть массив объектов, которые имеют 2 поля ключа и типа, поле типа - это практика или теория

Результат:

  1. сгруппировать массив по ключу

  2. преобразовать массив: в новом массиве объект с практикой типов должен находиться в четном индексе, а объект с теорией типов должен быть в нечетном индексе. (проверьте ввод и вывод, если мое объяснение неясно)

вот мой код, но он не работает должным образом при преобразовании массива

function transformArray(arr) {
  const grouped = arr.reduce((result, item) => {
    const key = item.key;
    if (!result[key]) {
      result[key] = { key, values: [] };
    }
    result[key].values.push(item);
    return result;
  }, {});

  for (const group in grouped) {
    const values = grouped[group].values;
    const newValues = [];
    for (let i = 0; i < values.length; i++) {
      const item = values[i];
      if (item.type === 'practice' && i % 2 === 0) {
        newValues.push(item);
      } else if (item.type === 'theory' && i % 2 === 1) {
        newValues.push(item);
      }
    }
    grouped[group].values = newValues;
  }

  return Object.values(grouped);
}

пример ввода:

const input = [
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'theory' },
{ key: 'A', type: 'theory' },

{ key: 'B', type: 'practice' },
{ key: 'B', type: 'theory' },
{ key: 'B', type: 'practice' },

{ key: 'C', type: 'practice' },
{ key: 'C', type: 'theory' },
{ key: 'C', type: 'practice' },
]

ВЫВОД должен быть следующим

[
  {
    key: 'A',
    values: [
      { key: 'A', type: 'practice'},  // index = even ==> practice
      { key: 'A', type: 'theory' },    // index = odd ==> theory
      { key: 'A', type: 'practice'}, // index = even ==> practice
      { key: 'A', type: 'theory'}, // index = odd ==> theory
    ],
  },
  {
    key: 'B',
    values: [
      { key: 'B', type: 'practice' },
      { key: 'B', type: 'theory',},
      { key: 'B', type: 'practice' },
    ],
  },
  {
    key: 'C',
    values: [
      { key: 'C', type: 'practice' },
      { key: 'C', type: 'theory', },
      { key: 'C', type: 'practice'},
    ],
  },
]

мой код немного сломан, и мне интересно, как добиться такого вывода?

Пожалуйста, приведите минимально воспроизводимый пример - что значит "работает не так, как ожидалось"?

jonrsharpe 12.04.2023 18:56

У меня есть ввод и вывод, и я подробно объяснил, как это должно работать

Mohamed Ahmed 12.04.2023 18:57

это похоже на чередование практики и теории. почему все проверки if. нельзя просто заменить 0,2..

cmgchess 12.04.2023 19:03

@cmgchess не могли бы вы объяснить подробнее, пожалуйста

Mohamed Ahmed 12.04.2023 19:04

я имел в виду, почему не что-то вроде values.forEach((e,i) => i%2===0 ? e.type = 'practice' : e.type = 'theory'); . без необходимости писать newValues ​​и grouped[group].values ​​= newValues;

cmgchess 12.04.2023 19:08

@cmgchess Я не могу этого сделать, потому что у объекта больше полей (не только type и key), но я не добавлял их сюда, потому что это было бы бесполезно, и если я делаю ваши решения, это означает, что я меняю объект, и я не хочу этого делать

Mohamed Ahmed 12.04.2023 19:13

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

cmgchess 12.04.2023 19:15

@cmgchess можете предоставить фрагмент кода

Mohamed Ahmed 12.04.2023 19:19
const newValues = values.map((e,i) => { const type = i%2===0 ? 'practice' :'theory' return ({...e,type}) }); grouped[group].values = newValues;
cmgchess 12.04.2023 19:25

@cmgchess const type = i % 2 === 0 ? 'practice' : 'theory'; return { ...e, type }; этот код изменит объект, я не хочу этого делать

Mohamed Ahmed 12.04.2023 19:34

так сделать копию сгруппированных и изменить его?

cmgchess 12.04.2023 19:51

@cmgchess как?

Mohamed Ahmed 12.04.2023 19:53

Кстати, что не должно быть мутировано. значения функции сгруппированного объекта, а на выходе отображается измененный сгруппированный объект

cmgchess 12.04.2023 19:58

объекты не могут быть видоизменены, мы не можем заменить тип типом

Mohamed Ahmed 12.04.2023 20:00

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

cmgchess 12.04.2023 20:05
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
15
79
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Все это можно сделать за одно использование метода reduce:

const input = [
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'practice' },
{ key: 'A', type: 'theory' },
{ key: 'A', type: 'theory' },

{ key: 'B', type: 'practice' },
{ key: 'B', type: 'theory' },
{ key: 'B', type: 'practice' },

{ key: 'C', type: 'practice' },
{ key: 'C', type: 'theory' },
{ key: 'C', type: 'practice' },
]

const output = input.reduce((prev, current) => {
  if (!prev[current.key]?.key){
    prev[current.key] = {
      key: '',
      values: []
    };
  }
  const object =  prev[current.key];
  object.key = current.key;
  object.values.push({
    key: current.key,
    type: ''
  });
  const index = object.values.length - 1;
  const keys = ['practice', 'theory'];
  if (keys.includes(current.type)) {
    object.values[index].type =  index % 2 === 0 ?  keys[0] : keys[1];
  } else{
    object.values[index].type = current.type;
  }
  
  return prev;
}, {})

console.info(output);

Downvote не мой, но ваш код изменяет значения вместо того, чтобы «сортировать» их определенным образом. В реальном коде могут быть дополнительные поля, специфичные для записи. Например {type: 'practice', exercise: 1 } vs {type: 'theory', page: 10}. Вообще говоря, изменение аргументов — плохая идея.

Yury Tarabanko 12.04.2023 23:25

@Yury TarabankoЕсли вы добавите в свой код объекты без key, он тоже сломается. Или {"key":"D","type":"practice"} - тоже будет ошибка. И любые другие типы, кроме указанных, будут игнорироваться.

imhvost 13.04.2023 00:08
Ответ принят как подходящий

Я предлагаю вам не сжимать все в одну функцию, а вместо этого реализовать несколько небольших служебных функций (для этого вы можете использовать библиотеку, например lodash).

Таким образом, у вас есть 2 отдельных шага использования

  1. Сгруппировать массив по ключу, а затем по типу
  2. Чередуйте два массива для практики и теории.

function transform(arr) {
  const result = []

  for (const [key, value] of groupBy('key', arr).entries()) {
    const byType = groupBy('type', value)

    result.push({
      key,
      values: interleave(
        byType.get('practice') ?? [], byType.get('theory') ?? [],
      ),
    })
  }

  return result

}


const input = [{"key":"A","type":"practice"},{"key":"A","type":"practice"},{"key":"A","type":"theory"},{"key":"A","type":"theory"},{"key":"B","type":"practice"},{"key":"B","type":"theory"},{"key":"B","type":"practice"},{"key":"C","type":"practice"},{"key":"C","type":"theory"},{"key":"C","type":"practice"}]

console.info(transform(input))

// Utils
function groupBy(by, arr) {
  const out = new Map

  for (const item of arr) {
    const key = item[by]

    if (out.has(key)) {
      out.get(key).push(item)
    } else {
      out.set(key, [item])
    }
  }

  return out
}

function interleave(a, b) {
  const out = []
  const len = Math.max(a.length, b.length)

  for (let i = 0; i < len; i++) {
    if (i < a.length) out.push(a[i])
    if (i < b.length) out.push(b[i])
  }

  return out
}

Другие вопросы по теме