I have a below list val list = listOf("o=one", "t...
# announcements
v
I have a below list val list = listOf("o=one", "t=two", "t=two", "f=four", "o=one", "t=two", "s=seven", "o=one") I wanna split it into list of the list contains [["o=one", "t=two", "t=two", "f=four"],["o=one", "t=two", "s=seven"],["o=one"]] Actually I want to group list by "o=" delimiter and the list will always have at least one "o=" value. How could I achieve this in Kotlin without creating mutable temp variables because of my code should be in the functional style? I have tried with group() and groupBy{} methods but couldn't get the expected result.
c
I think I'd first map them to a temporary class, then groupBy, then map them back to a string
d
Not the most efficient but.... you could use
scan
to count the number of `o=`s before (and including) each element, then group by this count.
j
Copy code
fun <A> List<A>.splitBy(pred : (A) -> Boolean) : List<List<A>> {
    if(size == 0) return listOf()
    val loc = indexOfLast(pred)
    if(loc == -1) return listOf(this)
    return subList(0, loc).splitBy(pred) + listOf(subList(loc, size))
}

val list = listOf("o=one", "t=two", "t=two", "f=four", "o=one", "t=two", "s=seven", "o=one")
list.splitBy { it.startsWith("o=") }
//[[o=one, t=two, t=two, f=four], [o=one, t=two, s=seven], [o=one]]
It's not stack safe or necessarily efficient, but very readable.
Tail recursive version:
Copy code
fun <A> List<A>.splitBy(pred : (A) -> Boolean) : List<List<A>> {
    tailrec fun List<A>.go(pred : (A) -> Boolean, suffix : List<List<A>>) : List<List<A>> {
        val loc = indexOfLast(pred)
        return when {
            size == 0 -> suffix
            loc == -1 -> listOf(this) + suffix
            else -> subList(0, loc).go(pred, listOf(subList(loc,size)) + suffix)
        }
    }
    return go(pred, listOf())
}
v
@Jakub Pi Thank you so much for your time and solution. It fullfils my requirement. I completely forgotten the recursive way of doing it. I'm pretty new to FP style, so it's really tough for me to code without var keyword 😊
d
Copy code
@ExperimentalStdlibApi
fun dummy() {
    val list = listOf("o=one", "t=two", "t=two", "f=four", "o=one", "t=two", "s=seven", "o=one")
    list.asSequence()
        .map { (if (it[0] == 'o') 1 else 0) to it }
        .scanReduce { (count, _), (inc, s) -> (count + inc) to s }
        .groupBy({ it.first }, { it.second })
        .values
        .toList()
}
👍 2