skip to Main Content

I’m trying to do this: I have an array of objects with the detail of a sale, with this format:

[
 {
   product:Banana,
   quantity:34,
  ...(other fields)
 },
 {
   product:Apple,
   quantity:11,
  ...(other fields)
 },
 {
   product:Banana,
   quantity:15,
  ...(other fields)
 },
 {
   product:Apple,
   quantity:9,
  ...(other fields)
 },
 {
   product:Orange,
   quantity:7,
  ...(other fields)
 }
]

From that array, I’d like to create a new one, with just one field by each product existing in the original array, and the total quantity of every product on the detail, like this:

[
 {
   product:Banana,
   quantity:49 //(34 + 15) from the original array

 },
 {
   product:Apple,
   quantity:20 //(11 + 9) from the original array

 },
 
 {
   product:Orange,
   quantity:7 //Just 7 from the original array
 }
]

Currently, I have this code which actually works (the variable names are in spanish):

                const validarDetalle  = async function (detalle) { 
                //'detalle' is the original array received by parameter
            
                   
                    let error=false;
                    
                    
                    
                    let arrayProductosCantidades=[]; //This is the new array which I'm generating
                
                    //I iterate on the original array with a for
                    for (const elemDetalle of detalle) {
                
                            console.log(elemDetalle);
                            //When the new array it's initially empty, I just concatenate
                            //the first product and quantity found on the original array to it
    
                            if(arrayProductosCantidades.length==0) {
                
                                arrayProductosCantidades=arrayProductosCantidades.concat(
                                {
                                    producto:elemDetalle.producto,
                                    cantidad:Number(elemDetalle.cantidad)
                    
                                });
                            }
                
                            //If it isn't empty, I look if the product of the element
                            //of the original array 
                            //where I'm standing already exists on the new array
                            else if(
                                (!arrayProductosCantidades.some (
                                    function(productoCantidad) {
                                        return (productoCantidad.producto == elemDetalle.producto)
                                    }
                                 )
                                )
                            )
                
                            {
                
                            //If it doesn't exists, I concatenate an element to the new array
                            //with the product and quantity of that element of the original array
                            arrayProductosCantidades=arrayProductosCantidades.concat(
                                {
                                    producto:elemDetalle.producto,
                                    cantidad:Number(elemDetalle.cantidad)
                    
                                }
                                );
                            }
                            //If the product already exists on the new array,
                            //I create a variable 'elementoProductoCantidad' with the
                            //previous value of that element in the new array
                            else{
                                let elementoProductoCantidad=
                                arrayProductosCantidades.find (
                                    function(productoCantidad) {
                                        return(productoCantidad.producto == elemDetalle.producto)
                
                                    }
                                 );
                                 //In that variable, I update the quantity field, adding to it the quantity
                                 //of the element of the original array in where I'm standing 
                                 elementoProductoCantidad.cantidad += Number(elemDetalle.cantidad);
    
             //After that, I delete the element of the new array with the old quantity value
                             arrayProductosCantidades=arrayProductosCantidades.filter(prodCant => prodCant.producto!=elemDetalle.producto);
    
            //Finally I concatenate it again, with the quantity value updated
arrayProductosCantidades=arrayProductosCantidades.concat(elementoProductoCantidad);
                                }
                        }
                        
                        console.log(arrayProductosCantidades);
                
                        
                //Once I've generated the new array, I make a validation for every product existing in my database 
                //(I should never get a negative stock in any product sold)
    
                        for (const elemProdCant of arrayProductosCantidades) {
                
                            const producto = await Number(elemProdCant.producto);
                            const cantidad = await Number(elemProdCant.cantidad);
            
                            let productoActualizado= await Producto.findById(elemProdCant.producto);
                            
                
                            if(Number(productoActualizado.stock) - Number(cantidad) < 0) {
                                error=true;
                            }
                        }
                    
                
                    return error;
                
                }

Althrough this works fine, I think it should be a better way to do this in a functional way, using functions like map and reduce instead of for loops.

Does anyone have an idea if this it’s possible and/or convenient?
Thank’s a lot!

2

Answers


  1. One easy way would be to first build a quantityByProduct object (lookup table) that contains the total quantity for each product and then use that to construct the final array of objects.

    const inputs = [{
      product: 'Banana',
      quantity: 34,
    }, {
      product: 'Apple',
      quantity: 11,
    }, {
      product: 'Banana',
      quantity: 15,
    }, {
      product: 'Apple',
      quantity: 9,
    }, {
      product: 'Orange',
      quantity: 7,
    }];
    
    const quantityByProduct = {};
    for (let input of inputs) {
      quantityByProduct[input.product] = quantityByProduct[input.product] || 0;
      quantityByProduct[input.product] += input.quantity;
    }
    
    const output = [];
    for (let product in quantityByProduct) {
      const quantity = quantityByProduct[product];
      output.push({
        product,
        quantity
      });
    }
    
    console.log(output);
    Login or Signup to reply.
  2.     const arr = [{
        product: 'Banana',
        quantity: 34,
        },
        {
            product: 'Apple',
            quantity: 11,
    
        },
        {
            product: 'Banana',
            quantity: 15,
    
        },
        {
            product: 'Apple',
            quantity: 9,
    
        },
        {
            product: 'Orange',
            quantity: 7,
        }
    ];
    
    const partition = (arr, fn, fn2) =>
        arr.reduce(
            (acc, val, i, arr) => {
                acc[fn(val, i, arr) ? 0 : fn2(val, i, arr) ? 1: 2].push(val);
                return acc;
            },
            [[], [], []]
        );
    
    const isBanana = obj => obj.product === 'Banana';
    const isApple = obj => obj.product === 'Apple';
    
    const result = partition(arr, isBanana, isApple).map((p) => {
        return {
            product: p[0].product,
            quantity: p.reduce((acc, val) => acc + val.quantity, 0),
        }
    });
    
    console.log(result); // [{ product: 'Banana', quantity: 49 },{ product: 'Apple', quantity: 20 },{ product: 'Orange', quantity: 7 }]
    

    The above code utilizes functional methods to consolidate liked objects

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search