package moe.kageru.spektacles import kotlin.collections.LinkedHashMap // maybe try this instead? // https://arrow-kt.io/docs/recursion/intro/ sealed class Node(open val value: Any) { class Leaf(override val value: List) : Node(value) class Split(val children: Map>) : Node(children) class Value(override val value: T) : Node(value) fun map(op: (T) -> R): Node { return when (this) { is Leaf -> Leaf(value.map(op)) is Value -> Value(op(value)) is Split -> Split(children.mapValues { it.value.map(op) }) } } fun groupBy(keyGenerator: (T) -> K): Node { return when (this) { is Leaf -> Split(value.groupBy(keyGenerator).mapValues { Leaf(it.value) }) is Value -> this is Split -> Split(children.mapValues { it.value.groupBy(keyGenerator) }) } } override fun toString() = asString() private fun asString(depth: Int = 0): String { return when (this) { is Leaf -> value.joinToString(indent(depth), prefix = "\n${indent(depth)}") is Value -> value.toString() is Split -> children.entries.joinToString("") { "\n${indent(depth)}${it.key}: ${it.value.asString(depth + 1)}" } } } fun countLeafs(): Node { return when (this) { is Leaf -> Value(value.size) is Value -> Value(1) is Split -> Split(children.mapValues { it.value.countLeafs() }) } } private fun indent(depth: Int) = (0..(depth * 2)).joinToString("") { " " } } fun Node.sort(): Node { return when (this) { is Node.Leaf -> this is Node.Value -> this is Node.Split -> Node.Split(this.children.sortByValues().mapValues { it.value.sort() }) } } private fun Map>.sortByValues(): Map> { val sortedEntries = entries.sortedBy { when (val v = it.value) { is Node.Value -> v.value is Node.Leaf -> v.value.size is Node.Split -> Int.MAX_VALUE } } return LinkedHashMap>().apply { for ((key, value) in sortedEntries) { this[key] = value } } }