0

I have currently two objects in my cartProducts array and the size will grow more in future. I am trying to calculate the sum of all items prices in products for all the objects. I have tried to use forEach but it seems to work slowly. How can I calculate the sum of prices in a faster way? I saw that using reduce is fine but as there are a lot of nested objects, I cannot figure out how to use it.

{
    "cartProducts": [
        {
            "id": "1",
            "products": [
                {
                    "id": "123",
                    "supplier": "Milkinis",
                    "items": [
                        {
                            "id": "14553",
                            "name": "eggs",
                            "price": "1.56",
                        },
                        {
                            "id": "14554",
                            "name": "flour",
                            "price": "1.98",
                        },
                    ]
                },
                {
                    "id": "124",
                    "supplier": "Lindy",
                    "items": [
                        {
                            "id": "14553",
                            "name": "chocolate",
                            "price": "4.5",
                        },
                    ]
                }
            ]
        },
        {
            "id": "2",
            "products": [
                {
                    "id": "125",
                    "supplier": "Wisk",
                    "items": [
                        {
                            "id": "14553",
                            "name": "water",
                            "price": "3.56",
                        },
                    ]
                }
            ]
        },
    ]
}
Enchantres
  • 853
  • 2
  • 9
  • 22
  • 1
    How many elements do you have that you think it's working slowly? You wouldn't get much performance advantage using different methods. – Konrad Aug 15 '22 at 09:14
  • so, you'll need to sum the cartProducts as a sum of the products – Jaromanda X Aug 15 '22 at 09:15
  • 1
    As Konrad said, the specific way you do the loop for this is unlikely to really matter from a performance perspective. `forEach` is perfectly good for this, or a `for-of` loop, or just a basic `for` loop. Despite the fact `forEach` calls a function, the cost of that is really low and *really* unlikely to matter. (The nesting argues for recursion, not `reduce`. `reduce` is fine in its context -- functional programming with predefined, reusable reducer functions -- but otherwise it's just an overcomplicated, easy-to-get-wrong loop.) – T.J. Crowder Aug 15 '22 at 09:16
  • I don't think using reduce will improve performance because it'll loop through the array as well just like forEach would. But it's certainly a bit more concise. You can check out the answer here to get some idea of using reduce https://stackoverflow.com/questions/73342247/how-do-i-calculate-the-total-of-multiple-items/73342309#73342309 – long_hair_programmer Aug 15 '22 at 09:18
  • Depending on the size of the dataset and the operations you'll be performing on it, one strategy that you can use is to persist the sum, and update it as you add a new item in the array. This way you won't have to recompute the sum via a loop everytime. But make sure you also update the sum when you're removing an element or updating the price of an existing element. – long_hair_programmer Aug 15 '22 at 09:21
  • 1
    `data.cartProducts.reduce((g,{products})=>g+products.reduce((i,{items})=>i+items.reduce((p,{price})=>+price+p,0),0),0);` – Jaromanda X Aug 15 '22 at 09:21

2 Answers2

1

Here is the code using reduce

sum = obj.cartProducts.reduce((acc, cart) => {
  return acc + cart.products.reduce((acc, product) => {
    return acc + product.items.reduce((acc, item) => {
      return acc + parseFloat(item.price);
    }, 0);
  }, 0);
}, 0);

console.log(sum);
<script>
  var obj = {
    "cartProducts": [{
        "id": "1",
        "products": [{
            "id": "123",
            "supplier": "Milkinis",
            "items": [{
                "id": "14553",
                "name": "eggs",
                "price": "1.56",
              },
              {
                "id": "14554",
                "name": "flour",
                "price": "1.98",
              },
            ]
          },
          {
            "id": "124",
            "supplier": "Lindy",
            "items": [{
              "id": "14553",
              "name": "chocolate",
              "price": "4.5",
            }, ]
          }
        ]
      },
      {
        "id": "2",
        "products": [{
          "id": "125",
          "supplier": "Wisk",
          "items": [{
            "id": "14553",
            "name": "water",
            "price": "3.56",
          }, ]
        }]
      },
    ]
  };
</script>

About performance of reduce vs loop look here Javascript performance: reduce() vs for-loop

Thanks

mplungjan
  • 169,008
  • 28
  • 173
  • 236
lablnet
  • 135
  • 2
  • 12
1

If you have no quantity, perhaps this would be fast enough

const cartStr = JSON.stringify(cart)
const prices = [...cartStr.matchAll(/"price":"(\d+\.\d+)"/g)]
  .reduce((acc, [_,match]) => acc += +match,0)
console.log(prices)
<script>
const cart = {
    "cartProducts": [
        {
            "id": "1",
            "products": [
                {
                    "id": "123",
                    "supplier": "Milkinis",
                    "items": [
                        {
                            "id": "14553",
                            "name": "eggs",
                            "price": "1.56",
                        },
                        {
                            "id": "14554",
                            "name": "flour",
                            "price": "1.98",
                        },
                    ]
                },
                {
                    "id": "124",
                    "supplier": "Lindy",
                    "items": [
                        {
                            "id": "14553",
                            "name": "chocolate",
                            "price": "4.5",
                        },
                    ]
                }
            ]
        },
        {
            "id": "2",
            "products": [
                {
                    "id": "125",
                    "supplier": "Wisk",
                    "items": [
                        {
                            "id": "14553",
                            "name": "water",
                            "price": "3.56",
                        },
                    ]
                }
            ]
        },
    ]
}
</script>
mplungjan
  • 169,008
  • 28
  • 173
  • 236