La Función groupBy En Kotlin

En este tutorial discutiremos el uso de la función groupBy en Kotlin, para convertir listas en mapas y cuyas entradas sean agrupadas por el criterio que establezcas.

Sintaxis De groupBy

La función groupBy te permite dividir todos los elementos de una colección en grupos. Dichos grupos son representados por un mapa cuya clave es el criterio de agrupación aplicado y los valores son listas que representan cada grupo.

Ejemplo de la función groupBy en Kotlin

La ilustración anterior muestra como agrupamos la lista L = [ -2, -1, 0, 1 ] al usar como clave el resultado de la expresión x < 0, la función groupBy recorrerá cada elemento determinando a que clave pertenece.

El resultado es un mapa con la clave true a la que pertenecen los negativos [-2, -1] y false apuntando a una lista a la que pertenecen los positivos y cero [0, 1]. Esto puedes representarlo en Kotlin de la siguiente forma:

fun main() {
    val numbers = listOf(-2, -1, 0, 1)
    println(numbers.groupBy { it < 0 }) // {true=[-2, -1], false=[0, 1]}
}

La siguiente es la sintaxis de la función groupBy:

// Arreglos
inline fun <T, K> Array<out T>.groupBy(
    keySelector: (T) -> K
): Map<K, List<T>>

// Iterables
inline fun <T, K> Iterable<T>.groupBy(
    keySelector: (T) -> K
): Map<K, List<T>>

// Strings
inline fun <K> CharSequence.groupBy(
    keySelector: (Char) -> K
): Map<K, List<Char>>

El parámetro de entrada se comporta como el selector de clave (keySelector) siendo del tipo función T->K. Esto quiere decir que para cada valor T, se elegirá como clave al valor final que sea expresado en K.

La cantidad de grupos dependerá de la cantidad de resultados posibles que K pueda tomar.

fun main() {
    val numbers = listOf(-2, -1, 0, 1)    

    println(numbers.groupBy { 1 }) // {1=[-2, -1, 0, 1]}
    println(numbers.groupBy { it }) // {-2=[-2], -1=[-1], 0=[0], 1=[1]}
    println(numbers.groupBy { it.sign }) // {-1=[-2, -1], 0=[0], 1=[1]}
    println(numbers.groupBy { it / 2 }) // {-1=[-2], 0=[-1, 0, 1]}
    println("hola".groupBy { "Caracteres" }) // {Caracteres=[h, o, l, a]}
}

En los ejemplos anteriores vemos diferentes casos al aplicar una función lambda para la clave. Si usas literales como 1 y "Caracteres", todos los elementos estarán bajo estas claves constantes.

En el caso de usar la referencia it, se creará una clave por cada elemento si el valor es diferente.

O si usas operaciones cuyos resultados tienen un rango de resultados repetitivo, como llamar a la propiedad sign o dividir por 2, la agrupación será más acotada por los pocos valores existentes.

Ejemplo De groupBy

Considera una clase que representa a las cartas de un videojuego a partir de su nombre y costo de utilización. Se requiere agrupar las cartas por el su costo e imprimir solo los nombres de las mismas, a partir de una lista dada.

data class Card(val name: String, val cost: Int)

fun main() {
    val hand = listOf(
        Card("Porrazo", 2),
        Card("Eviscerar", 0),
        Card("Embaucar", 2),
        Card("Ladrona de baritas", 1),
        Card("Alucinación", 1)
    )

    hand.groupBy { it.cost }.forEach { (cost, cards) ->
        println("$cost = ${cards.map { it.name }}")
    }
}

Salida:

2 = [Porrazo, Embaucar]
0 = [Eviscerar]
1 = [Ladrona de baritas, Alucinación]

El código usa groupBy{} sobre la lista hand aplicando como selector de clave el resultado de la propiedad cost.

Al agruparlas por costo, tomamos el mapa resultante e invocamos la función forEach{ } para imprimir en líneas separadas los grupos.

Al desestructurar la declaración a (cost, cards) podremos imprimir el costo junto al mapeado del nombre con la función map{} sobre cada grupo de cartas.

Como resultado tenemos la impresión de los costos 0, 1 y 2 junto a cada carta miembro.

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!