Sumar valores de propiedad de objeto JavaScript con la misma propiedad de objeto B en una matriz de objetos

Resuelto AlecPerkey asked hace 11 años • 13 respuestas

¿Cómo se tomaría una matriz de objetos de JavaScript, como

objArr = [
    {key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
    {key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
    {key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
    {key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54} // <- duplicate key
]

¿Y fusionar claves duplicadas sumando los valores?

Para obtener algo como esto:

reducedObjArr = [
    {key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:96},
    {key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
    {key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23}
]

Intenté iterar y agregar a una nueva matriz, pero esto no funcionó:

var reducedObjArr = [];
var item = null, key = null;
for(var i=0; i<objArr.length; i++) {
    item = objArr[i];
    key = Object.keys(item)[0];
    item = item[key];

    if(!result[key]) {
        result[key] = item;
    } else {
       result[key] += item;
    }
}a
AlecPerkey avatar Oct 08 '13 02:10 AlecPerkey
Aceptado

En lugar de usar un bucle for y enviar valores, puede usar directamente map y reducir :

let objArr = [
  {key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42},
  {key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78},
  {key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23},
  {key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}
];

// first, convert data into a Map with reduce
let counts = objArr.reduce((prev, curr) => {
  let count = prev.get(curr.key) || 0;
  prev.set(curr.key, curr.val + count);
  return prev;
}, new Map());

// then, map your counts object back to an array
let reducedObjArr = [...counts].map(([key, value]) => {
  return {key, value}
})

console.log(reducedObjArr);
Expandir fragmento

Hamms avatar Jun 03 '2016 21:06 Hamms

Deberías asignar cada objeto no encontrado al resultado con su .keypropiedad.

Si lo encuentra, deberá agregarlo .val.

var temp = {};
var obj = null;
for(var i=0; i < objArr.length; i++) {
   obj=objArr[i];

   if(!temp[obj.key]) {
       temp[obj.key] = obj;
   } else {
       temp[obj.key].val += obj.val;
   }
}
var result = [];
for (var prop in temp)
    result.push(temp[prop]);

Además, parte del problema era que estabas reutilizando la itemvariable para hacer referencia al valor de .key, por lo que perdiste la referencia al objeto.

user2736012 avatar Oct 07 '2013 19:10 user2736012

Reducción más simple que la publicada en otros lugares ya que no utiliza un elemento de mapa

const objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54}];

const output = objArr.reduce((accumulator, cur) => {
  let date = cur.key;
  let found = accumulator.find(elem => elem.key === date)
  if (found) found.val += cur.val;
  else accumulator.push(cur);
  return accumulator;
}, []);

console.log(output)
Expandir fragmento

mplungjan avatar Nov 20 '2019 10:11 mplungjan

Podrías usar una tabla hash para agrupar por key.

var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54}],
    grouped = [];

array.forEach(function (o) {
    if (!this[o.key]) {
        this[o.key] = { key: o.key, val: 0 };
        grouped.push(this[o.key]);
    }
    this[o.key].val += o.val;
}, Object.create(null));

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Expandir fragmento

Otro enfoque es recopilar todos los pares clave/valor en Mapy formatear la matriz final con Array.fromuna devolución de llamada para los objetos.

var array = [{ key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 42 }, { key: 'Mon Sep 24 2013 00:00:00 GMT-0400', val: 78 }, { key: 'Mon Sep 25 2013 00:00:00 GMT-0400', val: 23 }, { key: 'Mon Sep 23 2013 00:00:00 GMT-0400', val: 54 }],
    grouped = Array.from(
        array.reduce((m, { key, val }) => m.set(key, (m.get(key) || 0) + val), new Map),
        ([key, val]) => ({ key, val })
    );

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Expandir fragmento

Nina Scholz avatar Jan 13 '2017 19:01 Nina Scholz

var objArr = [
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:42},
{key:"Mon Sep 24 2013 00:00:00 GMT-0400", val:78},
{key:"Mon Sep 25 2013 00:00:00 GMT-0400", val:23},
{key:"Mon Sep 23 2013 00:00:00 GMT-0400", val:54}]

var targetObj = {};
for (var i = 0; i < objArr.length; i++) {
  if (!targetObj.hasOwnProperty(objArr[i].key)) {
    targetObj[objArr[i].key] = 0;
  }
  targetObj[objArr[i].key] += objArr[i].val;
}

console.log(targetObj);
Expandir fragmento

Explosion Pills avatar Oct 07 '2013 19:10 Explosion Pills