More Kotlin (PartitionBy)

The existing Kotlin Collection utilities that transforms the collection into output collections as groups or sub-groups have certain limitations

group-by The key is associated with a list of corresponding elements

Only returns Map<Key, List>

partition The pair of lists contains elements partitioned by a predicate function

Only returns two partitions as Pair<List, List>

windowed The sized windows slide over the List in fixed steps

Windowed has fixed size and step of List<List>

chunked The list of sub lists not exceeding size specified

Chunked has upper bound size of List<List>

How do We solve problems where We want the output to be collections of different sizes ?:

4clojure problem 30 - remove consecutive duplicates

4clojure problem 31 - variable length partitions

Compress a sequence of characters simliar to clojure.core/partition-by

Apply a function to each value in a List, creating a partition each time the identity function returns a new value

fun main(args: Array<String>) {
   
fun <T> identity(): (T) -> T = { it }

tailrec fun <T, R> partitionBy(
    source: Iterable<T>,
    partition: (T) -> R,
    result: Sequence<List<T>> = sequenceOf()
): Sequence<List<T>> =
    if (source.none())
        result
    else {
        val taken = source.takeWhile { partition(it) == partition(source.first()) }
        partitionBy(source.drop(taken.count()), partition, result + sequenceOf(taken))
        // kotlin.collections/partition can be used recursively returns pair of ArrayList
        //val (taken, rest) = source.partition { source.first() == partition(it) }
        //partitionBy(rest, partition, result + sequenceOf(taken))
    }
    
   val leroy1 = partitionBy("Leeeeeerrroyyy".asIterable(), identity())
   
   // for problem/30 also use https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/distinct.html 
   
   println(leroy1.map { it.first() }.toList().joinToString("")) 
   
   val leroy2 = partitionBy("Leeeeeerrroyyy".asIterable(), identity())
   
   //Add Run Length to leroy2
   println(leroy2.map { it.first() to it.size }.toList().joinToString(":"))    
   
}