Estoy tratando de crear un gráfico de barras apiladas, pero no sé cómo remodelar mis datos.
Los datos que provienen del backend se ven como a continuación, donde tienen una date y una clave de category
[ {date: 'January', category: 'A'}, {date: 'January', category: 'B'}, {date: 'February', category: 'A'}, {date: 'February', category: 'B'}, {date: 'February', category: 'C'}, {date: 'February', category: 'B'}, ... ]Necesito remodelar estos datos en el formulario que se muestra a continuación, donde los agrupará en sus respectivos meses y luego contará la cantidad de veces que se vio cada categoría.
[ {name: 'January', countA: 1, countB: 1, countC: 0 }, {name: 'February', countA: 1, countB: 2, countC: 1 } ... ] Hasta ahora, solo he podido contar el número total de categorías por mes usando la función de reduce como
const filterData = data.reduce((groups, curr) => { const {January = 0, February = 0, ...} = groups; switch(curr.date){ case 'January': return {...groups, January: January + 1} case 'February': return {...groups, February: February + 1} ... } }, {})Pero esto no funcionará para el gráfico de barras apiladas.
Puede usar Array#reduce con un objeto para almacenar los recuentos de cada mes.
let arr = [ {date: 'January', category: 'A'}, {date: 'January', category: 'B'}, {date: 'February', category: 'A'}, {date: 'February', category: 'B'}, {date: 'February', category: 'C'}, {date: 'February', category: 'B'}, ]; let res = Object.values(arr.reduce((acc, {date, category})=>{ ++(acc[date] ??= {date, countA: 0, countB: 0, countC: 0})['count' + category]; return acc; }, {})); console.log(res);Según su pregunta, no podemos estar seguros de que solo haya tres categorías, por lo que aquí hay una solución que se ocupará de n de ellas. Es más largo de lo que puede querer, pero espero que no sea demasiado detallado. (He usado un bucle for...of en lugar de reduce al final, pero puedes intercambiarlos si quieres).
const data = [ {date: 'March', category: 'Z'}, {date: 'January', category: 'A'}, {date: 'January', category: 'B'}, {date: 'February', category: 'A'}, {date: 'November', category: 'D'}, {date: 'February', category: 'M'}, {date: 'February', category: 'B'}, {date: 'February', category: 'C'}, {date: 'February', category: 'B'}, {date: 'January', category: 'D'} ]; // Create a deduped array of elements with // a `count[letter]` format by creating // a Set of mapped categories const catArr = new Set(data.map(obj => { return `count${obj.category}`; })); // Create a new counts object from the set // setting each count property to 0 const counts = {}; for (const count of catArr) { counts[count] = 0; } // Iterate over the data. If the date key isn't // on the output object, add it and set it where // one of the properties is the date, and the others // are a copy of the categories const out = {}; for (const obj of data) { const { date, category } = obj; const count = `count${category}`; out[date] = out[date] || { name: date, ...counts }; ++out[date][count]; } // Get the values of the output object console.log(Object.values(out));Dado que las otras respuestas han cubierto enfoques usando reduce y for...of , agregaré otro enfoque que es bastante sencillo, usando forEach .
Más sobre forEach aquí: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
let months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; let cleanData =[]; let dirtyData = []; // get original data dirtyData = getData(); // iterate through each month months.forEach(month => { let monthEntries = dirtyData.filter( e => e.date == month); let aCount = 0; let bCount = 0; let cCount = 0; // for each month, count how many enteries there were in each category monthEntries.forEach(e => { switch (e.category.toLowerCase()){ case "a": aCount++; break; case "b": bCount++; break; case "c": cCount++; break; } }); // push the data to a new cleanData array in our preferred format cleanData.push({name: month, countA: aCount, countB: bCount, countC: cCount}) }); // log results console.log(cleanData); // function to retreive original data function getData() { return [ {date: 'January', category: 'A'}, {date: 'January', category: 'B'}, {date: 'February', category: 'A'}, {date: 'February', category: 'B'}, {date: 'February', category: 'C'}, {date: 'March', category: 'B'}, {date: 'March', category: 'A'}, {date: 'March', category: 'B'}, {date: 'March', category: 'C'}, {date: 'March', category: 'B'}, {date: 'April', category: 'A'}, {date: 'April', category: 'B'}, {date: 'April', category: 'C'}, {date: 'April', category: 'B'}, {date: 'May', category: 'A'}, {date: 'May', category: 'B'}, {date: 'May', category: 'C'}, {date: 'May', category: 'B'}, {date: 'May', category: 'A'}, {date: 'May', category: 'B'}, {date: 'May', category: 'C'}, {date: 'May', category: 'B'}, {date: 'May', category: 'A'}, {date: 'May', category: 'B'}, {date: 'June', category: 'C'}, {date: 'June', category: 'B'}, {date: 'June', category: 'A'}, {date: 'July', category: 'B'}, {date: 'July', category: 'C'}, {date: 'July', category: 'B'}, {date: 'July', category: 'A'}, {date: 'July', category: 'B'}, {date: 'August', category: 'C'}, {date: 'September', category: 'B'}, {date: 'September', category: 'A'}, {date: 'September', category: 'B'}, {date: 'October', category: 'C'}, {date: 'October', category: 'B'}, {date: 'October', category: 'A'}, {date: 'October', category: 'B'}, {date: 'November', category: 'C'}, {date: 'November', category: 'A'}, {date: 'December', category: 'B'}, {date: 'December', category: 'B'}, ]; }