Home > Blockchain >  Guaranteed order of groupingBy aggregate Map in Kotlin
Guaranteed order of groupingBy aggregate Map in Kotlin

Time:12-10

I am using a groupingBy and then aggregate to process a list of items and group them into pairs. The order of the input list is important, and the resulting list should also be ordered.

aggregate returns a Map indicating that the processing order is not preserved.

Example:

    data class Foo(val a: Int, val b: String)

    val r1 = Foo(1, "a")
    val r2 = Foo(1, "b")
    val r3 = Foo(2, "c")
    val r4 = Foo(2, "d")
    val r5 = Foo(2, "e")
    val records = listOf(r1, r2, r3, r4, r5)

    val result = records.groupingBy { it.a }
        .aggregate { _, acc: Pair<Int, List<String>>?, element, _ ->
            if (acc == null) {
                element.a to listOf(element.b)
            } else {
                acc.first to acc.second   element.b
            }
        }.values.toList()

    println(result)

Returns [(1, [a, b]), (2, [c, d, e])] - which is the correct order, but is it guaranteed?

PLEASE NOTE that this is a simple example that may be sorted by a - but that is NOT the solution, as the records sorting is provided by the user of the function.

CodePudding user response:

If you want to be sure that the Pairs of the aggregation result are ordered, you could do:

fun main() {
    data class Foo(val a: Int, val b: String)

    val r1 = Foo(2, "a")
    val r2 = Foo(2, "b")
    val r3 = Foo(1, "c")
    val r4 = Foo(1, "d")
    val r5 = Foo(2, "e")
    val records = listOf(r1, r2, r3, r4, r5)

    val result = records.groupingBy { it.a }
        .aggregate { _, acc: Pair<Int, List<String>>?, element, _ ->
            if (acc == null) {
                element.a to listOf(element.b)
            } else {
                acc.first to acc.second   element.b
            }
        }.values.sortedBy {it.first}.toList()

    println(result)
}

This would output [(1, [c, d]), (2, [a, b, e])].

CodePudding user response:

aggregate's documentation does not guarantee this, but mutableMapOf's documentation does guarantee it. So I would use aggregateTo(mutableMapOf()) { /*...*/ } to future-proof your code. The fact that they don't guarantee it means either they forgot to, or they deliberately want to keep open the option of switching the underlying implementation for performance in the future.

  • Related