Tengo esta matriz de objetos.
const items = [ { id: '121', itemDate: '2022-04-28', itemName: 'testname1', itemCategory: 'Category A', itemPrice: { price: '100', currency: 'GBP' }, createdBy: { username: 'user1', name: 'Name 1', date: '2022-04-28T22:41:59', }, }, { id: '122', itemDate: '2022-04-28', itemName: 'testname2', itemCategory: 'Category B', itemPrice: { price: '100', currency: 'GBP' }, createdBy: { username: 'user2', name: 'Name 2', date: '2022-04-28T22:42:44', }, }, { id: '122', itemDate: '2022-04-28', itemName: 'testname3', itemCategory: 'Category C', itemPrice: { price: '200', currency: 'GBP' }, createdBy: { username: 'user2', name: 'Name 2', date: '2022-04-28T22:43:16', }, }, ]
Código que estoy usando:
items.reduce(function (c, x) { if (!c[x.createdBy.username]) c[x.createdBy.username] = { username: x.createdBy.username, total: 0, } c[x.createdBy.username].total += Number(x.itemPrice.price) return c }, [])
Esta parte me da el siguiente resultado:
items :>> [ user1: { username: 'user1', total: 100}, user2: { username: 'user2', total: 300} ]
Así que probé esto para deshacerme de los nombres de los objetos:
let output = [] let totalSum = 0 for (const username in items) { let temp = { username: items[username].username, total: items[username].total, } totalSum = totalSum + items[username].total output.push(temp) } output.push({ username: 'allUsers', total: totalSum }) return output
Y el resultado final es como lo quiero ahora:
output :>> [ { username: 'user1', total: 100 }, { username: 'user2', total: 300 }, { username: 'allUsers', total: 400} ]
Mis dos preguntas...
¿Hay alguna manera de actualizar la parte .reduce
para obtener un objeto sin el nombre al principio, sin tener que usar el ciclo for?
¿Hay también una forma de implementar la parte que sumaría todos los totales?
Gracias
Ejemplo de código (sin comentarios/descripción)
const groupAndAdd = arr => ( Object.values( arr.reduce( (acc, {createdBy : {username}, itemPrice: {price}}) => { acc.allUsers ??= { username: 'allUsers', total: 0}; acc.allUsers.total += +price; if (username in acc) { acc[username].total += +price; } else { acc[username] = {username, total: +price}; } return acc; }, {} ) ) );
A continuación se presenta una demostración de trabajo para lograr el objetivo deseado, con notas/comentarios para ayudar a comprender.
Fragmento de código
// method to group by user and sum prices const groupAndAdd = arr => ( // extract the values from the intermediate result-object Object.values( arr.reduce( // generate result as object (acc, {createdBy : {username}, itemPrice: {price}}) => { // above line uses de-structuring to directly access username, price // below uses logical nullish assignment to set-up "allUsers" acc.allUsers ??= { username: 'allUsers', total: 0}; // accumulate the "price" to the all-users "total" acc.allUsers.total += +price; // if "acc" (accumulator) has "username", simply add price to total if (username in acc) { acc[username].total += +price; } else { // create an object for the "username" with initial total as "price" acc[username] = {username, total: +price}; } // always return the "acc" accumulator for ".reduce()" return acc; }, {} // initially set the "acc" to empty object ) ) // if required, use ".sort()" to move the all-users to last position in array ); const items = [{ id: '121', itemDate: '2022-04-28', itemName: 'testname1', itemCategory: 'Category A', itemPrice: { price: '100', currency: 'GBP' }, createdBy: { username: 'user1', name: 'Name 1', date: '2022-04-28T22:41:59', }, }, { id: '122', itemDate: '2022-04-28', itemName: 'testname2', itemCategory: 'Category B', itemPrice: { price: '100', currency: 'GBP' }, createdBy: { username: 'user2', name: 'Name 2', date: '2022-04-28T22:42:44', }, }, { id: '122', itemDate: '2022-04-28', itemName: 'testname3', itemCategory: 'Category C', itemPrice: { price: '200', currency: 'GBP' }, createdBy: { username: 'user2', name: 'Name 2', date: '2022-04-28T22:43:16', }, }, ]; console.log('group and add prices per user: ', groupAndAdd(items));
.as-console-wrapper { max-height: 100% !important; top: 0 }
Explicación
Se agregaron comentarios en línea al fragmento anterior.
PD: si desea agregar valor a la comunidad stackoverflow,
Por favor considere leer: Qué hacer cuando mi pregunta es respondida ¡Gracias!
Para su primera pregunta, está inicializando correctamente como una matriz, pero está usando solo un objeto. Dos formas en que puedes hacer esto.
Primera opción
let something = items.reduce(function(c, x) { if (!c[x.createdBy.username]) c[x.createdBy.username] = { username: x.createdBy.username, total: 0, } c[x.createdBy.username].total += Number(x.itemPrice.price) return c }, {}); something = Object.values(something);
Segunda opción
Estaba pensando en usar solo empujar, pero parece que no es posible, por lo que la anterior es la única opción.
Es posible usar push, pero se volverá demasiado complicado al verificar con find y actualizar el elemento de matriz correcto.
Para su segunda pregunta de sumar todos los totales, puede usar la sintaxis simple de:
const sum = arr.reduce((a, c) => a + c, 0);
Este es el código mínimo que necesita para sumar una matriz de números.