pnkj
pnkj

Reputation: 498

How to group and merge list in kotlin?

For example, I have the follwing list:

data:[
    {
        year:2017,
        price:10
    },
    {
        year:2017,
        price:19
    },
    {
        year:2020,
        price:15
    },
    {
        year:2021,
        price:100
    },
    {
        year:2020,
        price:20
    }
]

My purpose is to merge the price of list by the same year. As the example list show: the result need to be:

data:[
    {
        year:2017,
        price:29
    },
    {
        year:2020,
        price:35
    },
    {
        year:2021,
        price:100
    }
]

Is there any way to achieve it quickly? Like groupingby,map...?

Upvotes: 2

Views: 4983

Answers (3)

riddhee
riddhee

Reputation: 111

You can achieve it by using this also

data class Sales(
    val year: Int,
    val price: Int
)

    fun main(args: Array<String>) {

        val salesByYear = listOf(
            Sales(2017, 10),
            Sales(2017, 19),
            Sales(2020, 15),
            Sales(2021, 100),
            Sales(2020, 20),
            Sales(2016, 500),
            Sales(2021, 320)
        )
        
        var list = ArrayList<Sales>();

        
        salesByYear.groupBy(Sales::year).mapValues { entry ->
            list.add(Sales(entry.key, entry.value.map { it.price }.sumBy { it })) }

        println(list)
    }

Output will be as follows

 [Sales(year=2017, price=29),
 Sales(year=2020, price=35), 
Sales(year=2021, price=420), 
Sales(year=2016, price=500)]

Upvotes: 5

TreffnonX
TreffnonX

Reputation: 2930

I added some overhead to make this compile.

The essence is to group all Year-Price-Tuples by year, then reduce each group to one element (by summing up the prices). I also added a conversion back to a list, and sorted by year.

data class Sales(val year: Int, val price: Int)

val myList = listOf(
    Sales(2017, 10),
    Sales(2017, 19),
    Sales(2020, 15),
    Sales(2021, 100),
    Sales(2020, 20),
)

fun main () {
    val reduced = myList.groupBy({ it.year }, { it })
          .mapValues { it.value.reduce{ left, right ->
              Sales(left.year, (left.price + right.price)) } }
          .values
          .sortedBy { it.year }
    reduced.forEach { println("${it.year}: ${it.price}") }
}

This yields:

2017: 29
2020: 35
2021: 100

Upvotes: 2

mightyWOZ
mightyWOZ

Reputation: 8315

First you have to define a grouping on basis of year and then perfrom a aggregation reduction on all group elements

// ListElementType is the type of objects stored in the list
yourList.groupingBy { it.year }.aggregate{key:Int, accumulator:Long?, element:ListElementType, first:Boolean ->
        accumulator?.plus(element.price)?.toLong() ?: element.price.toLong()
}.toList()

Upvotes: 1

Related Questions