У меня есть массив объектов, которые имеют 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'},
],
},
]
мой код немного сломан, и мне интересно, как добиться такого вывода?
У меня есть ввод и вывод, и я подробно объяснил, как это должно работать
это похоже на чередование практики и теории. почему все проверки if. нельзя просто заменить 0,2..
@cmgchess не могли бы вы объяснить подробнее, пожалуйста
я имел в виду, почему не что-то вроде values.forEach((e,i) => i%2===0 ? e.type = 'practice' : e.type = 'theory');
. без необходимости писать newValues и grouped[group].values = newValues;
@cmgchess Я не могу этого сделать, потому что у объекта больше полей (не только type
и key
), но я не добавлял их сюда, потому что это было бы бесполезно, и если я делаю ваши решения, это означает, что я меняю объект, и я не хочу этого делать
если вы не хотите мутировать, используйте карту. также вы можете расширить логику. я только что выложил это здесь
@cmgchess можете предоставить фрагмент кода
const newValues = values.map((e,i) => { const type = i%2===0 ? 'practice' :'theory' return ({...e,type}) }); grouped[group].values = newValues;
@cmgchess const type = i % 2 === 0 ? 'practice' : 'theory'; return { ...e, type };
этот код изменит объект, я не хочу этого делать
так сделать копию сгруппированных и изменить его?
@cmgchess как?
Кстати, что не должно быть мутировано. значения функции сгруппированного объекта, а на выходе отображается измененный сгруппированный объект
объекты не могут быть видоизменены, мы не можем заменить тип типом
я понимаю, я думаю. Вам нужно смешать их, а не менять, чтобы они образовывали альтернативную практику и теорию
Все это можно сделать за одно использование метода 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Если вы добавите в свой код объекты без key
, он тоже сломается. Или {"key":"D","type":"practice"}
- тоже будет ошибка. И любые другие типы, кроме указанных, будут игнорироваться.
Я предлагаю вам не сжимать все в одну функцию, а вместо этого реализовать несколько небольших служебных функций (для этого вы можете использовать библиотеку, например lodash
).
Таким образом, у вас есть 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
}
Пожалуйста, приведите минимально воспроизводимый пример - что значит "работает не так, как ожидалось"?