#javascript #arrays #group-by
#javascript #массивы #группировать по
Вопрос:
У меня есть массив объектов. Я хочу сгруппировать их по определенному полю.
[
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
]
Результат, который я ожидаю для группировки по имени атрибута, выглядит следующим образом.
{
// Group #1
"JOHN": [
{
"type": 2,
"sum": 200
}
{
"type": 1,
"sum": 5
}
],
// Group #2
"SERA":[
{
"type": 1,
"sum": 43
},
{
"type": 2,
"sum": 129
},
]
}
Я использовал вложенные циклы, но, к сожалению, скорость выполнения была низкой, и это не давало правильных результатов.
Комментарии:
1. может ли вывод также быть полностью заключен в
{ }
квадратные скобки? таким образом, полный результат — это объект, а не массив? Я думаю, в противном случае это невозможно2. @Saeed Вывод синтаксически некорректен
3. @caramba Да, он может быть полностью заключен в
{ }
квадратные скобки.
Ответ №1:
Как вы уже упоминали, мы можем использовать объект вместо массива для самой внешней оболочки. А также поменять местами внутри одного объекта на массив, тогда это возможное решение.
var data = [{"name": "JOHN","type": 1,"sum": 5},{"name": "SERA","type": 1,"sum": 43},{"name": "SERA","type": 2,"sum": 129},{"name": "JOHN","type": 2,"sum": 200}];
var newData = {};
data.forEach( (item) => {
if (!(item['name'] in newData)) {
newData[item['name']] = [];
}
newData[item['name']].push(
{
'type': item['type'],
'sum' : item['sum']
}
);
});
console.log(newData);
Ответ №2:
Предлагаемая вами структура вывода недопустима, однако с помощью Array.reduce
вы можете создать объект, в котором все свойства являются массивами объектов:
const data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
const result = data.reduce((c, {name, type, sum}) => {
c[name] = c[name] || [];
c[name].push({type, sum});
return c;
}, {});
console.log(result);
Ответ №3:
Еще один способ с forEach
destructuring
??
помощью оператора and
const merge = (arr) => {
const obj = {};
arr.forEach(({ name, ...rest }) => (obj[name] ??= []).push(rest));
return obj;
};
const data = [
{
name: "JOHN",
type: 1,
sum: 5,
},
{
name: "SERA",
type: 1,
sum: 43,
},
{
name: "SERA",
type: 2,
sum: 129,
},
{
name: "JOHN",
type: 2,
sum: 200,
},
];
console.log(merge(data));
Ответ №4:
Вы можете использовать эту функцию, которая позволяет Array.prototype.reduce
преобразовать исходные данные в другую структуру массива.
let data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
function groupedBy(data, field) {
let fieldValues = [...data].reduce((acc, current) => {
return acc.concat(current[field]);
}, []).filter((value, index, self) => {
return self.indexOf(value) === index;
});
let results = fieldValues.reduce((acc, item) => {
let items = [...data].filter(el => {
return el.name === item;
});
items.forEach(i => delete i.name);
return Object.assign(acc, { [item]: items});
}, {});
return results;
}
console.log(groupedBy(data, "name"));