Вход -
[
{color:'red', shape:'circle', size:'medium'},
{color:'red', shape:'circle', size:'small'}
]
Выход -
[
{color:'red', shape:'circle', size:['medium','small']}
]
Как это может быть достигнуто в Javascript?
Да, я ищу идеальное решение, которое может обрабатывать повторяющиеся свойства в объектах.
Но тогда, как говорит @Cal Irvine, что вы ожидаете получить на выходе, когда ввод выглядит примерно так: [ {color:'red', shape:'circle', size:'medium'}, {color:'red', shape:'circle', size:'small'}, {color:'red', shape:'square', size:'small'}, {color:'blue', shape:'circle', size:'medium'}]
? Как вы будете группировать предметы?
Возможный дубликат Группировать элементы массива с помощью объекта
В этом случае я ожидал бы вывода [ {цвет: «красный», форма: «круг», размер: [«средний», «маленький»]}, {цвет: «красный», форма: «квадрат», размер :'маленький'}, {цвет:'синий', форма:'круг', размер:'средний'}]
Вы можете создать общую функцию, которая принимает в качестве параметров массив объектов и массив ключей.
Вы можете сделать это, выполнив следующие действия:
reduce()
для массива объектов и установите аккумулятор в пустой массив []
filter()
на Object.keys()
forEach()
другие клавиши и поместите значения в соответствующий массив.reduce()
const arr = [
{color:'red', shape:'circle', size:'medium'},
{color:'red', shape:'circle', size:'small'}
]
function groupByProps(arr,props){
const res = arr.reduce((ac,a) => {
let ind = ac.findIndex(b => props.every(k => a[k] === b[k]));
let others = Object.keys(a).filter(x => !props.includes(x));
if (ind === -1){
ac.push({...a});
others.forEach(x => ac[ac.length - 1][x] = []);
ind = ac.length - 1
}
others.forEach(x => ac[ind][x].push(a[x]));
return ac;
},[])
return res;
}
const res = groupByProps(arr,['color','shape'])
console.info(res)
Если вы просто хотите сгруппировать на основе color
и shape
, вы можете использовать reduce
. Создайте объект-аккумулятор с каждой уникальной комбинацией этих двух свойств, разделенных ключом |
. И объект, который вы хотите на выходе, как их значение. Затем используйте Object.values()
, чтобы получить эти объекты в виде массива.
const input = [
{color:'red', shape:'circle', size :'medium'},
{color:'red', shape:'circle', size:'small'},
{color:'blue', shape:'square', size:'small'}
];
const merged = input.reduce((acc, { color, shape, size }) => {
const key = color + "|" + shape;
acc[key] = acc[key] || { color, shape, size: [] };
acc[key].size.push(size);
return acc
}, {})
console.info(Object.values(merged))
Вот как выглядит объединенный/аккумулятор:
{
"red|circle": {
"color": "red",
"shape": "circle",
"size": [
"medium",
"small"
]
},
"blue|square": {
"color": "blue",
"shape": "square",
"size": [
"small"
]
}
}
Вы можете сделать его динамическим, создав массив ключей, которые вы хотите сгруппировать:
const input = [
{ color: 'red', shape: 'circle', size: 'medium' },
{ color: 'red', shape: 'circle', size: 'small' },
{ color: 'blue', shape: 'square', size: 'small' }
];
const groupKeys = ['color', 'shape'];
const merged = input.reduce((acc, o) => {
const key = groupKeys.map(k => o[k]).join("|");
if (!acc[key]) {
acc[key] = groupKeys.reduce((r, k) => ({ ...r, [k]: o[k] }), {});
acc[key].size = []
}
acc[key].size.push(o.size)
return acc
}, {})
console.info(Object.values(merged))
Вот простая функция groupBy
, которая принимает массив объектов и массив props
для группировки:
let data = [
{color:'red', shape:'circle', size:'medium'},
{color:'red', shape:'circle', size:'small'}
]
let groupBy = (arr, props) => Object.values(arr.reduce((r,c) => {
let key = props.reduce((a,k) => `${a}${c[k]}`, '')
let otherKeys = Object.keys(c).filter(k => !props.includes(k))
r[key] = r[key] || {...c, ...otherKeys.reduce((a,k) => (a[k] = [], a),{})}
otherKeys.forEach(k => r[key][k].push(c[k]))
return r
}, {}))
console.info(groupBy(data, ['color','shape']))
Идея состоит в том, чтобы использовать Массив.уменьшить и, по сути, создать строковый ключ переданного реквизита. Для других полей создайте массив и сохраняйте туда значения на каждой итерации.
Вы хотите, чтобы [ {цвет: 'красный', форма: 'квадрат', размер: 'маленький'}, {цвет: 'красный', форма: 'круг', размер: 'маленький'}] выводился [ {цвет: 'red', shape:['circle', 'square'], size:'small'} ] и как бы вы поступили в случае, когда есть три объекта, и все они соответствуют двум общим, но не одинаковым две вещи? Будет ли когда-нибудь только два предмета?