Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

145
Vistas
Group by array with key with another array of values

I have the following object:

var series = [{
    name: 'Series 1',
    data: [1400, 999, 450],
    tag: "Tag 1"
}, {
    name: 'Series 2',
    data: [355, 188, 99],
    tag: "Tag 1"
}, {
    name: 'Series 3',
    data: [205, 488, 104],
    tag: "Tag 2"
}];

What I'm trying to do is to perform a groupBy function to that array so for example, calling orderBy("tag") should return the following output:

[{
    name: "Series 1 / Series 2",
    data: [1755, 1187, 549], // => Sum: Series1[0] + Series2[0], Series1[1] + Series2[1], etc...
    tag: "Tag 1"
},  {
    name "Series 3",
    data: [205, 488, 104],
    tag: "Tag 2"
}]

At the moment this is what I've so far:

var seriesArray = [{
            name: 'Series 1',
            data: [1400, 999, 450],
            tag: "Tag 1"
        }, {
            name: 'Series 2',
            data: [355, 188, 99],
            tag: "Tag 1"
        }, {
            name: 'Series 3',
            data: [205, 488, 104],
            tag: "Tag 2"
        }];

const groupBy = (key) => seriesArray.reduce((total, currentValue) => {
  const newTotal = total;
  if (
    total.length &&
    total[total.length - 1][key] === currentValue[key]
  )
    newTotal[total.length - 1] = {
      ...total[total.length - 1],
      ...currentValue,
      data: parseInt(total[total.length - 1].data[0]) + parseInt(currentValue.data[0]),
    };
  else newTotal[total.length] = currentValue;
  return newTotal;
}, []);

console.log(groupBy('tag'));

As you can see it seems to work the orderBy("tag") but I'm doing the sum operation explicit, the main problem with this is that data[] could have X elements.

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

Currently your approach assumes that the last item that was added to your total array has the same key that you're trying to group on. This is all good if the data is sorted by key (ie: all "Tag 1"s come first), but can be an issue if its not. I would suggest that instead, you first build an object/Map that is keyed by tag. That way you can use the object to find your accumulated "Tag 1", "Tag 2", etc... objects. Once you've reduced it to an object/Map, you can grab the values (which are the accumulated objects) and put them into an array. To handle the different data array lengths, you can use .map() on your accumulated data array (ie: seen.data) and then add each number with the corresponding number from the current object's data array using the index argument i:

const seriesArray = [{ name: 'Series 1', data: [1400, 999, 450], tag: "Tag 1" }, { name: 'Series 2', data: [355, 188, 99], tag: "Tag 1" }, { name: 'Series 3', data: [205, 488, 104], tag: "Tag 2" }];

const groupBy = (arr, key) => Array.from(arr.reduce((map, currentObj) => {
  const groupOnKey = currentObj[key];
  const seen = map.get(groupOnKey);
  return map.set(groupOnKey, seen ? {
    ...seen,
    name: seen.name + " / " + currentObj.name,
    data: seen.data.map((num, i) => num + currentObj.data[i], 0)
  } : currentObj);
}, new Map()).values());

console.log(groupBy(seriesArray, 'tag'));

about 4 years ago · Juan Pablo Isaza Denunciar

0

Good challenge, this occurs to me with findIndex

const groupBy = (key) => seriesArray.reduce((total, currentValue) => {
  index = total.findIndex(x => x[key] === currentValue[key])
  if (index >= 0) {
    total[index].data = total[index].data.map(function (num, idx) {
      return num + parseInt(currentValue.data[idx]);
    }); 
    total[index].name += " / " + currentValue.name;
  } else {
    total.push(currentValue);
  }
  return total;
}, []);
about 4 years ago · Juan Pablo Isaza Denunciar

0

I think the logic in your reduce callback function is not going to give you the result you want. I'll explain what that function is doing.

  1. First iteration total is an empty array as this is the initial value so the conditions is false and the else block is executed and adding the first element of the array to the new array
  2. Second iteration total now has one element which has the same tag as the current element so if statement is true and code is executed which would override the first element, which is why name becomes Serie 2 instead of Serie 1 and data is a number instead of an array with the value equals to the sum of current.data[0] + total[0].data[0] = 1755
  3. Third iteration if statement does not match and else block is executed adding the third element to total array. Also note that using total.length -1 is not covering the case when the second item doesn't actually match if you try to switch the order between serie 2 and serie 3 you will not get serie 1 and serie 2 grouped by tag.

What you want to do

var seriesArray = [{
    name: 'Series 1',
    data: [1400, 999, 450],
    tag: "Tag 1"
  },
  {
    name: 'Series 3',
    data: [1400, 999, 450],
    tag: "Tag 2"
  }, {
    name: 'Series 2',
    data: [355, 188, 99],
    tag: "Tag 1"
  },
];

const isMatchingArray = (array1, array2) => {
  if (array1.length !== array2.length) {
    return false;
  }
  for (let i = 0; i < array1.length; i++) {
    if (array1[i] !== array2[i]) {
      return false;
    }
  }
  return true;
}

const groupBy = (key, array) => array.reduce((total, currentValue) => {
  const newTotal = total;
  if (total.length) {
    const matchingItemIndex = total.findIndex(element => {
      if (typeof element[key] === 'string') {
        return element[key] === currentValue[key];
      } else if (Array.isArray(element[key])) {
        return isMatchingArray(element[key], currentValue[key]);
      }
    });
    if (matchingItemIndex !== -1) {
      newTotal[matchingItemIndex] = {
        ...total[matchingItemIndex],
        ...currentValue,
        name: total[matchingItemIndex].name + ' / ' + currentValue.name,
        data: currentValue.data.map((dataItem, index) => parseInt(dataItem + total[matchingItemIndex].data[index])),
      };
    } else {
      newTotal.push(currentValue)
    }
  } else {
    newTotal.push(currentValue)
  };
  return newTotal;
}, []);

console.log(groupBy('tag', seriesArray))
console.log(groupBy('data', seriesArray));

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda