Reputation: 63
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.
The resulting JSON should look like
[{
"addons": [
{
"addonId": "Addon_5035fac357f446fb8b4fcff45d2e36e5",
"addonIdentifier": "Gherkin",
"addonQuantity": 1,
"subTotal": 0.99,
"addonType": "EXTRAS"
},
{
"addonId": "Addon_700a1458fae54ba9b3e148da709eea4a",
"addonIdentifier": "Hash Brown",
"addonQuantity": 1,
"subTotal": 0.99,
"addonType": "EXTRAS"
},
{
"addonId": "Addon_f4408295adb14723aa22a3a7e645a7a7",
"addonIdentifier": "Cheese",
"addonQuantity": 1,
"subTotal": 0.99,
"addonType": "EXTRAS"
}
],
"categoryId": "Addon_Cate_1a7bacd1a07b40ceb7d5d3a2229fb303",
"categoryIdentifier": "Extra 1"}]
Upvotes: 0
Views: 100
Reputation: 19562
If you have your data in, say, data classes that look like this:
data class Item(
val addons: List<Addon>,
val categoryId: String,
val categoryIdentifier: String
)
then there's lots of ways you can group them. The tricky part is that you have a list of addons for each item, and you really want them to be separate. Here's a few ways you could do it:
// group as Id -> List<List<Addon>>, then flatten those lists into a single List<Addon>
items.groupBy({it.categoryId}, {it.addons})
.mapValues { (_, addonLists) -> addonLists.flatten() }
(I'm using the groupBy(keySelector, valueSelector)
function where you decide what gets stored, and what it's grouped by)
// turn each Item into a list of (Id, Addon) pairs then group those
items.flatMap { item ->
item.addons.map { addon -> item.categoryId to addon }
}.groupBy({it.first}, {it.second})
The above things give you immutable collections - you can do this for the below too, but just to keep it simple as an example
// just make your own map - you could just use a for loop and add to a map too
items.fold(mutableMapOf<String, MutableList<Addon>>()) { groups, item ->
groups.apply {
getOrPut(item.categoryId) { mutableListOf() }
.addAll(item.addons)
}
}
Upvotes: 1
Reputation: 3445
(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)
Upvotes: 1
Reputation: 106
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.
Upvotes: 0