Сравнение соседних объектов в массиве и их слияние
Есть непонимание работы с переберающими свойствами массивов в javascript. У меня есть исходный массив, допустим, вот такой:
const arr = [
{text: 'stack', color: 'yellow', fontSize: '30px'},
{text: 'over', color: 'red', fontSize: '14px'},
{text: 'flow', color: 'red', fontSize: '14px'}
]`
И я хочу из него получить массив со следующими объектами:
const newArr = [
{text: 'stack', color: 'yellow', fontSize: '30px'},
{text: 'overflow', color: 'red', fontSize: '14px'}
]
Т.е. я пытаюсь сравнить объекты по ключам color и fontSize и если они совпадают - объединить текст и удалить ненужный объект. Пробовал решить через старый добрый for:
for (let i = 0; i < arr.length; i++) {
if (arr[i].fontSize === arr[i + 1].fontSize && arr[i].color === arr[i + 1].color) {
arr[i].text = arr[i].text + arr[i + 1].text;
finalArr.push(arr[i]);
} else {
finalArr.push(arr[i+1]);
}
}
Но цикл работает неверно, невозможно обработать последний объект массива. Да и хотелось бы узнать, как можно это решить с использованием ES6 синтаксиса.
Ответы (2 шт):
Для ваших задач простой цикл вполне подходит, так что я предложил вариант и с ним. Но если хотите использовать методы массивов (многие из них появились уже в ES5), можно попробовать reduce() (поскольку вам нужен массив с другим количеством элементов и элементы нужно менять, map() и filter() не очень подходят по назначению — хотя, наверное, можно ухитриться и с ними). Из совсем новых методов можно использовать flatMap(), хотя это, пожалуй, не самый очевидный вариант.
const arr = [
{text: 'stack', color: 'yellow', fontSize: '30px'},
{text: 'over', color: 'red', fontSize: '14px'},
{text: 'flow', color: 'red', fontSize: '14px'},
{text: 'stack', color: 'black', fontSize: '14px'},
{text: 'over', color: 'green', fontSize: '30px'},
{text: 'flow', color: 'green', fontSize: '30px'},
];
const finalArr = [];
for (let i = 0; i < arr.length; i++) {
const current = arr[i];
const next = arr[i + 1];
if (next && current.fontSize === next.fontSize && current.color === next.color) {
next.text = current.text + next.text;
} else {
finalArr.push(current);
}
}
console.log(finalArr);
const arr = [
{text: 'stack', color: 'yellow', fontSize: '30px'},
{text: 'over', color: 'red', fontSize: '14px'},
{text: 'flow', color: 'red', fontSize: '14px'},
{text: 'stack', color: 'black', fontSize: '14px'},
{text: 'over', color: 'green', fontSize: '30px'},
{text: 'flow', color: 'green', fontSize: '30px'},
];
const finalArr = arr.reduce(
(acc, current, i, array) => {
const next = array[i + 1];
if (next && current.fontSize === next.fontSize && current.color === next.color) {
next.text = current.text + next.text;
} else {
acc.push(current);
}
return acc;
},
[],
);
console.log(finalArr);
const arr = [
{text: 'stack', color: 'yellow', fontSize: '30px'},
{text: 'over', color: 'red', fontSize: '14px'},
{text: 'flow', color: 'red', fontSize: '14px'},
{text: 'stack', color: 'black', fontSize: '14px'},
{text: 'over', color: 'green', fontSize: '30px'},
{text: 'flow', color: 'green', fontSize: '30px'},
];
const finalArr = arr.flatMap(
(current, i, array) => {
const next = array[i + 1];
if (next && current.fontSize === next.fontSize && current.color === next.color) {
next.text = current.text + next.text;
return [];
} else {
return current;
}
}
);
console.log(finalArr);
Можно пойти таким путем. Он конечно изменяет исходный массив, но это легко исправить предварительно скопировав его.
const newArr = arr.reduce((acc, obj, index) => {
arr.forEach((el, idx) => {
if( obj && el && index !== idx && obj.color == el.color && obj.fontSize == el.fontSize ){
obj.text += el.text;
arr[idx] = null;
}
});
if(obj) acc.push(obj);
return acc;
}, []);
console.log(newArr);