Sumar claves similares en una matriz de objetos.
Tengo una serie de objetos como los siguientes:
[
{
'name': 'P1',
'value': 150
},
{
'name': 'P1',
'value': 150
},
{
'name': 'P2',
'value': 200
},
{
'name': 'P3',
'value': 450
}
]
Necesito sumar todos los valores de los objetos con el mismo nombre. (Probablemente también otras operaciones matemáticas como calcular el promedio). Para el ejemplo anterior, el resultado sería:
[
{
'name': 'P1',
'value': 300
},
{
'name': 'P2',
'value': 200
},
{
'name': 'P3',
'value': 450
}
]
Primero recorra la matriz e inserte el 'nombre' en la propiedad de otro objeto. Si la propiedad existe, agregue el 'valor' al valor de la propiedad; de lo contrario, inicialice la propiedad al 'valor'. Una vez que cree este objeto, repita las propiedades y envíelas a otra matriz.
Aquí hay un código:
var obj = [
{ 'name': 'P1', 'value': 150 },
{ 'name': 'P1', 'value': 150 },
{ 'name': 'P2', 'value': 200 },
{ 'name': 'P3', 'value': 450 }
];
var holder = {};
obj.forEach(function(d) {
if (holder.hasOwnProperty(d.name)) {
holder[d.name] = holder[d.name] + d.value;
} else {
holder[d.name] = d.value;
}
});
var obj2 = [];
for (var prop in holder) {
obj2.push({ name: prop, value: holder[prop] });
}
console.log(obj2);
Espero que esto ayude.
Un enfoque ES2024 para agrupar porname
Primero puede usar Map.groupBy
para agrupar su matriz name
donde Map
cada clave en el mapa es una name
de sus objetos y el valor es una matriz de objetos de su matriz con esa name
clave. Luego puede usar Array.from()
el grupo Map
para convertirlo en una matriz de objetos, donde para cada objeto, acumula los objetos para sumar value
con la misma name
clave usando .reduce()
:
const sumByKey = (arr, key, value) => {
const grouped = Map.groupBy(arr, o => o[key]);
return Array.from(
grouped.values(),
group => group.reduce((acc, obj) => ({...obj, [value]: (acc[value] ?? 0) + obj[value]}), {})
);
}
const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];
console.log(sumByKey(arr, 'name', 'value')); // [ { "name": "P1", "value": 300 }, { "name": "P2", "value": 200 }, { "name": "P3", "value": 450 } ]
Un enfoque ES6 para agrupar por name
:
Puede convertir su conjunto de objetos a Map
usando .reduce()
. El mapa tiene pares clave-valor, donde cada clave es name
y cada una value
es la suma acumulada de valores para esa name
clave en particular. Luego puede convertir fácilmente el Mapa nuevamente en una matriz usando Array.from()
, donde puede proporcionar una función de mapeo que tomará las claves/valores del Mapa y los convertirá en objetos:
const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];
const res = Array.from(arr.reduce(
(m, {name, value}) => m.set(name, (m.get(name) || 0) + value), new Map
), ([name, value]) => ({name, value}));
console.log(res);
Lo anterior es bastante compacto y no necesariamente el más fácil de leer. Sugeriría ponerlo en una función para que quede más claro lo que está haciendo. Si busca más código autodocumentado, usarlo for...of
puede hacer que lo anterior sea más fácil de entender. La siguiente función también es útil si desea agrupar o sumar claves con espacios:
const arr = [ { 'name': 'P1', 'value': 150 }, { 'name': 'P1', 'value': 150 }, { 'name': 'P2', 'value': 200 }, { 'name': 'P3', 'value': 450 } ];
const sumByKey = (arr, key, value) => {
const map = new Map();
for(const obj of arr) {
const currSum = map.get(obj[key]) || 0;
map.set(obj[key], currSum + obj[value]);
}
const res = Array.from(map, ([k, v]) => ({[key]: k, [value]: v}));
return res;
}
console.log(sumByKey(arr, 'name', 'value')); // 'name' = value to group by, 'value' = value to sum
Agrupar por algo más que solo name
:
Aquí hay un enfoque que debería funcionar si tiene otras propiedades superpuestas además de solo name
(las claves/valores deben ser los mismos en ambos objetos para que se "agrupen"). Implica iterar a través de su matriz y reducirla a Map que contiene pares clave-valor. Cada clave del nuevo Mapa es una cadena de todos los valores de propiedad por los que desea agrupar y, por lo tanto, si la clave de su objeto ya existe, entonces sabrá que es un duplicado, lo que significa que puede agregar el valor actual del objeto al objeto almacenado. . Finalmente, puede utilizar Array.from()
para transformar su mapa de pares clave-valor en una matriz de valores justos:
const arr = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];
const res = Array.from(arr.reduce((acc, {value, ...r}) => {
const key = JSON.stringify(r);
const current = acc.get(key) || {...r, value: 0};
return acc.set(key, {...current, value: current.value + value});
}, new Map).values());
console.log(res);
Puede utilizar Array.reduce() para acumular resultados durante cada iteración.
var arr = [{'name':'P1','value':150},{'name':'P1','value':150},{'name':'P2','value':200},{'name':'P3','value':450}];
var result = arr.reduce(function(acc, val){
var o = acc.filter(function(obj){
return obj.name==val.name;
}).pop() || {name:val.name, value:0};
o.value += val.value;
acc.push(o);
return acc;
},[]);
console.log(result);