Issue
I have to group list items if the items fields are the same. Above in my code, it works what I want if every id is the same. But product ids are unique. For that reason, I cant make the right grouping.
Here I wrote an example product model but original product model has 20+ fields and some of them are object list. Product model is came from api.
I want to make grouping by item except for id.
data class Product(
val id: Int,
val name: String,
val price: Int,
val quantity: Int,
val subModels: List<SubModel>,
val values: List<String>
)
data class SubModel(
val name: String,
val value: String
)
data class GroupedProduct(
val product: Product,
val count: Int,
val totalQuantity: Int,
val isGroup: Boolean
)
var products = listOf(
Product(1, "p1", 10, 2, listOf(SubModel("a", "1")), listOf("a")),
Product(1, "p1", 10, 2, listOf(SubModel("a", "1")), listOf("a")),
Product(1, "p1", 10, 2, listOf(SubModel("b", "2")), listOf("a")),
Product(1, "p2", 12, 1, listOf(SubModel("a", "1")), listOf("a")),
Product(1, "p3", 12, 1, listOf(SubModel("a", "1")), listOf("a")),
)
var groupedPersons: MutableList<GroupedProduct> = mutableListOf()
products.groupBy { it }.forEach {
if (it.value.size > 1)
groupedPersons.add(GroupedProduct(it.key, it.value.size, it.value.getTotalQuantity(), true))
else
groupedPersons.add(GroupedProduct(it.key, it.value.size, it.value.size, false))
}
fun List<Product>.getTotalQuantity(): Int {
var totalQuantity = 0
forEach {
totalQuantity += it.quantity
}
return totalQuantity
}
groupedPersons.forEach {
println(it)
}
Prints:
GroupedProduct(product=Product(id=1, name=p1, price=10, quantity=2, subModels=[SubModel(name=a, value=1)], values=[a]), count=2, totalQuantity=4, isGroup=true)
GroupedProduct(product=Product(id=1, name=p1, price=10, quantity=2, subModels=[SubModel(name=b, value=2)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=1, name=p2, price=12, quantity=1, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=1, name=p3, price=12, quantity=1, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
When item ids are different grouping results be like that obviously.
GroupedProduct(product=Product(id=1, name=p1, price=10, quantity=2, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=2, name=p1, price=10, quantity=2, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=3, name=p1, price=10, quantity=2, subModels=[SubModel(name=b, value=2)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=4, name=p2, price=12, quantity=1, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=5, name=p3, price=12, quantity=1, subModels=[SubModel(name=a, value=1)], values=[a]), count=1, totalQuantity=1, isGroup=false)
Solution
You must replace the id with a meaningless id (like -1 in my example):
data class Product(
val id: Int,
val name: String,
val price: Int,
val quantity: Int
)
data class GroupedProduct(
val product: Product,
val count: Int,
val totalQuantity: Int,
val isGroup: Boolean
)
var products = listOf(
Product(1, "p1", 10, 2),
Product(2, "p1", 10, 2),
Product(3, "p1", 10, 2),
Product(4, "p2", 12, 1),
Product(5, "p3", 12, 1),
)
val result = products
.groupBy { it.copy(id = -1) }
.map { (_, values) ->
val product = values.first().copy(id = -1, quantity = values.sumOf { it.quantity })
GroupedProduct(product, values.count(), values.sumOf { it.quantity }, values.count() > 1)
}
result.forEach(::println)
Output:
GroupedProduct(product=Product(id=-1, name=p1, price=10, quantity=6), count=3, totalQuantity=6, isGroup=true)
GroupedProduct(product=Product(id=-1, name=p2, price=12, quantity=1), count=1, totalQuantity=1, isGroup=false)
GroupedProduct(product=Product(id=-1, name=p3, price=12, quantity=1), count=1, totalQuantity=1, isGroup=false)
Answered By - lukas.j
Answer Checked By - David Marino (JavaFixing Volunteer)