Home > Back-end >  Merge objects in an array based on key values
Merge objects in an array based on key values

Time:11-22

I have an array of objects whose ID is same but it contains the list of items which I want to merge in the same item. Below is the object I want the items of which to be merged on the basis of "categoryID"

`

[
  {
    "addons": [
      {
        "addonId": "Addon_5035fac357f446fb8b4fcff45d2e36e5",
        "addonIdentifier": "Gherkin",
        "addonQuantity": 1,
        "subTotal": 0.99,
        "addonType": "EXTRAS"
      }
    ],
    "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
    "categoryIdentifier": "Extra 1"
  },
  {
    "addons": [
      {
        "addonId": "Addon_700a1458fae54ba9b3e148da709eea4a",
        "addonIdentifier": "Hash Brown",
        "addonQuantity": 1,
        "subTotal": 0.99,
        "addonType": "EXTRAS"
      }
    ],
    "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
    "categoryIdentifier": "Extra 1"
  },
  {
    "addons": [
      {
        "addonId": "Addon_f4408295adb14723aa22a3a7e645a7a7",
        "addonIdentifier": "Cheese",
        "addonQuantity": 1,
        "subTotal": 0.99,
        "addonType": "EXTRAS"
      }
    ],
    "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
    "categoryIdentifier": "Extra 1"
  }
]

In the Above example, as you can see that the categoryId of all the items is same, thus I want to merge all the items in one and create one list of "Addons"

I have tried maps and group by but nothing has worked. Let me know if anything else is needed.

Want to merge the list so that items with similar "CategoryID" be merged in single item while adding the list of "Addons" in that item

CodePudding user response:

create one list of "Addons"

You already have that, your array is already a list of "Addon" entities.

Merging all the Addon object having the same categoryId will result in having one single Addon (hence you will lose all data on the individual addon - addonId, addonIdentifier etc - but one).

If you want to treat your category as a different object you should define a new "category" entity (with categoryId, categoryIdentifier etc). Then you can add new Addons having the categoryId field corresponding to the category it belongs to. Hope this answer your question.

CodePudding user response:

(Like Igor said, you should really post more code since it will make it easier for someone to respond to your question. In this case to show you how it could work I had to recreate all your model classes.. so next time)

You also don't say what is your preferred way to parse JSON, there are several options in Kotlin, I have chosen Jackson for this illustration

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import java.math.BigDecimal

fun main(args: Array<String>) {
    val mapper = JsonMapper.builder()
        .addModule(KotlinModule(strictNullChecks = true))
        .build()
    val categories: List<Category> = mapper.readValue(
        data,
        object : TypeReference<List<Category>>() {}
    )
    println(categories)
    val combinedCategories = categories
        .groupingBy { it.categoryId }
        .aggregate { key, accumulator: Category?, element: Category, first ->
            if(accumulator==null) {
                element
            }
            else {
                element.copy(
                    addons = accumulator.addons.plus(element.addons)
                )
            }
        }
        .values.toList()
    combinedCategories.forEach { category -> println(category) }
}

data class Category(
    val addons: List<AddOn>,
    val categoryId: String,
    val categoryIdentifier: String,
)

data class AddOn(
    val addonId: String,
    val addonIdentifier: String,
    val addonQuantity: Int,
    val subTotal: BigDecimal,
    val addonType: String,
)

val data = """
    [
      {
        "addons": [
          {
            "addonId": "Addon_5035fac357f446fb8b4fcff45d2e36e5",
            "addonIdentifier": "Gherkin",
            "addonQuantity": 1,
            "subTotal": 0.99,
            "addonType": "EXTRAS"
          }
        ],
        "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
        "categoryIdentifier": "Extra 1"
      },
      {
        "addons": [
          {
            "addonId": "Addon_700a1458fae54ba9b3e148da709eea4a",
            "addonIdentifier": "Hash Brown",
            "addonQuantity": 1,
            "subTotal": 0.99,
            "addonType": "EXTRAS"
          }
        ],
        "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
        "categoryIdentifier": "Extra 1"
      },
      {
        "addons": [
          {
            "addonId": "Addon_f4408295adb14723aa22a3a7e645a7a7",
            "addonIdentifier": "Cheese",
            "addonQuantity": 1,
            "subTotal": 0.99,
            "addonType": "EXTRAS"
          }
        ],
        "categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
        "categoryIdentifier": "Extra 1"
      },
      {
        "addons": [
          {
            "addonId": "Addon_2222222",
            "addonIdentifier": "Nuts",
            "addonQuantity": 10,
            "subTotal": 9.99,
            "addonType": "EXTRAS"
          }
        ],
        "categoryId": "Addon_Cate_222222",
        "categoryIdentifier": "Extra 2"
      }
    ]
""".trimIndent()

So the interesting bit is the groupingBy and aggregate methods. The aggregate functions takes the element (the Category) and an accumulator which is another Category what it mutated to merge the addons.

Output is

[Category(addons=[AddOn(addonId=Addon_5035fac357f446fb8b4fcff45d2e36e5, addonIdentifier=Gherkin, addonQuantity=1, subTotal=0.99, addonType=EXTRAS)], categoryId=Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303, categoryIdentifier=Extra 1), Category(addons=[AddOn(addonId=Addon_700a1458fae54ba9b3e148da709eea4a, addonIdentifier=Hash Brown, addonQuantity=1, subTotal=0.99, addonType=EXTRAS)], categoryId=Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303, categoryIdentifier=Extra 1), Category(addons=[AddOn(addonId=Addon_f4408295adb14723aa22a3a7e645a7a7, addonIdentifier=Cheese, addonQuantity=1, subTotal=0.99, addonType=EXTRAS)], categoryId=Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303, categoryIdentifier=Extra 1), Category(addons=[AddOn(addonId=Addon_2222222, addonIdentifier=Nuts, addonQuantity=10, subTotal=9.99, addonType=EXTRAS)], categoryId=Addon_Cate_222222, categoryIdentifier=Extra 2)]
Category(addons=[AddOn(addonId=Addon_5035fac357f446fb8b4fcff45d2e36e5, addonIdentifier=Gherkin, addonQuantity=1, subTotal=0.99, addonType=EXTRAS), AddOn(addonId=Addon_700a1458fae54ba9b3e148da709eea4a, addonIdentifier=Hash Brown, addonQuantity=1, subTotal=0.99, addonType=EXTRAS), AddOn(addonId=Addon_f4408295adb14723aa22a3a7e645a7a7, addonIdentifier=Cheese, addonQuantity=1, subTotal=0.99, addonType=EXTRAS)], categoryId=Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303, categoryIdentifier=Extra 1)
Category(addons=[AddOn(addonId=Addon_2222222, addonIdentifier=Nuts, addonQuantity=10, subTotal=9.99, addonType=EXTRAS)], categoryId=Addon_Cate_222222, categoryIdentifier=Extra 2)
  • Related