0

I would need to check if the objects in the "food" array are equal to each other, and the ones that are - combine into one adding amount and mody.amount and leaving the rest unchanged. This is just for better order data displaying. I tried with lodash library and reduce but but I don't know exactly how to construct this function that nested objects(mody) adds values ​​as well, and in case isEqual returns false keep the object while concurrently concatenating the identical ones.

What I tried:

obj1.reduce((prev, next) => _.isEqual(prev, next) ? {...prev, amount: prev.amount + next.amount} : next

Now it looks like that:

 const food =  [
    {
        "id": 1,
        "name": "chicken",
        "price": 6,
        "amount": 1,
        "mody": [
            {
                "id": 33,
                "name": "cheese",
                "price": 1,
                "amount": 1
            },
            {
                "id": 34,
                "name": "chips",
                "price": 2,
                "amount": 1
            }
        ]
    },
    {
        "id": 1,
        "name": "chicken",
        "price": 6,
        "amount": 1,
        "mody": [
            {
                "id": 33,
                "name": "cheese",
                "price": 1,
                "amount": 1
            },
            {
                "id": 34,
                "name": "chips",
                "price": 2,
                "amount": 1
            }
        ]
    },
    {
        "id": 2,
        "name": "pizza",
        "price": 6,
        "amount": 2,
        "mody": [
            {
                "id": 12,
                "name": "extra cheese",
                "price": 2,
                "amount": 1
            }
        ]
    }
]
  

and would need something like that:

const food = [
    {
        "id": 1,
        "name": "chicken",
        "price": 6,
        "amount": 2,
        "mody": [
            {
                "id": 33,
                "name": "cheese",
                "price": 1,
                "amount": 2
            },
            {
                "id": 34,
                "name": "chips",
                "price": 2,
                "amount": 2
            }
        ]
    },
    {
        "id": 2,
        "name": "pizza",
        "price": 6,
        "amount": 2,
        "mody": [
            {
                "id": 12,
                "name": "extra cheese",
                "price": 2,
                "amount": 1
            }
        ]
    }
]
  
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
brxu
  • 1
  • Does this answer your question? [Sum javascript object propertyA values with same object propertyB in array of objects](https://stackoverflow.com/questions/19233283/sum-javascript-object-propertya-values-with-same-object-propertyb-in-array-of-ob) – Heretic Monkey Mar 31 '21 at 21:08
  • Unfortunately not. There adds values ​​together but does not check if the objnects are equal and there are no deeper objects nested inside – brxu Apr 01 '21 at 11:18

1 Answers1

0

The algorithm to sum the food amounts and mody amounts are almost the same, the difference is that for each food that has the same id we will sum the mody amount. To make the algorithm simpler I used a dictionary as the accumulator on the reduce function so we have a unique element per key. This element will be our final food or mody with the amount sum.

Mody sum algoritm:

const sumMody = (modyAccumulator, currentMody) => {
  //Get the stored mody in the accumulator dictionary or null if it the mody is not stored
  const storedMody = modyAccumulator[currentMody.id] ?? null 
  
  // if mody is null then add mody to the dictionary using its id as key
  if (!storedMody) {
    modyAccumulator[currentMody.id] = currentMody
  } else {
    //Mody is stored then sum amount
    storedMody.amount += currentMody.amount
  }

  return modyAccumulator
}

The food sum algoritm is the same as the sumMody, the only difference is that it calls the sumMody function when the foods are equal:

const sumFood = (foodAccumulator, currentFood) => {
  //Get the stored foodin the accumulator dictionary or null if it the food is not stored
  const storedFood = foodAccumulator[currentFood.id] ?? null

  // if food is null then add food to the dictionary using its id as key
  if (!storedFood) {
    foodAccumulator[currentFood.id] = currentFood
  } else {
    //Food is stored then sum food amount
    storedFood.amount += currentFood.amount

    //Create a list with mody from both foods
    const modyList = [...storedFood.mody, ...currentFood.mody]

    //Use reduce passing the sumMody callback function and initialize the accumulator with a dictionary
    const modySumDictionary = modyList.reduce(sumMody, {})

    /* The function above return a dictionary where the identifier is the mody.id 
      and the value is the mody. We only need the values from that dictionary so 
      we use Object.values to extract all the values. */
    storedFood.mody = Object.values(modySumDictionary)
  }

  return foodAccumulator
}

To execute both sums:

//As explained before the reduce function will return a dictionary so we use Object.values to get only the values
const result = Object.values(food.reduce(sumFood, {}))

console.log(result)

Algoritm without comments:

const sumMody = (modyAccumulator, currentMody) => {
  const storedMody = modyAccumulator[currentMody.id] ?? null
  if (!storedMody) {
    modyAccumulator[currentMody.id] = currentMody
  } else {
    storedMody.amount += currentMody.amount
  }

  return modyAccumulator
}

const sumFood = (foodAccumulator, currentFood) => {
  const storedFood = foodAccumulator[currentFood.id] ?? null
  if (!storedFood) {
    foodAccumulator[currentFood.id] = currentFood
  } else {
    storedFood.amount += currentFood.amount

    const modyList = [...storedFood.mody, ...currentFood.mody]

    const modySumDictionary  = modyList.reduce(sumMody, {})
    storedFood.mody = Object.values(modySumDictionary)
  }

  return foodAccumulator
}

const result = Object.values(food.reduce(sumFood, {}))

console.log(result)

Reference to Object.values