Función shuffled En Kotlin

En este tutorial aprenderás sobre el uso de la función shuffled en Kotlin con el objetivo de permutar aleatoriamente los elementos de una colección. Adicionalmente verás el uso de shuffle para arreglos y listas mutables.

Función shuffled()

La función de extensión shuffled() baraja los elementos de una colección y retorna una lista con el nuevo orden aleatorio. Su sintaxis es la siguiente:

fun <T> Iterable<T>.shuffled(): List<T>

// Versión sobrecargada con generador Random
fun <T> Iterable<T>.shuffled(random: Random): List<T>

Veamos su uso a través de la permutación de una lista de números enteros:

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    val shuffledNumbers = numbers.shuffled()
    println(shuffledNumbers)
}

Salida aleatoria:

[2, 6, 5, 8, 3, 4, 7, 1]

Por otro lado, shuffled() puede recibir una instancia de un generador de números aleatorios Random. Por ejemplo, generemos cuatro formas aleatorias de ocupar las sillas de un cuarto entre cuatro personas:

import kotlin.random.Random

fun main() {
    val names = listOf("Carl", "Bona", "Robin", "Ana")
    println(names.shuffled(Random(1)))
    println(names.shuffled(Random(2)))
    println(names.shuffled(Random(3)))
    println(names.shuffled(Random(4)))
}
[Robin, Bona, Ana, Carl]
[Robin, Bona, Carl, Ana]
[Ana, Bona, Carl, Robin]
[Robin, Bona, Ana, Carl]

Al usar un entero como estado de semilla en el generador Random, se barajarán los elementos de una forma aleatoria que puede ser conservada si mantienes el uso de la misma semilla.

Función shuffle()

El equivalente de shuffled() en arreglos y listas mutables es la función shuffle(). Por la naturaleza de estas colecciones, la función no retorna ningún resultado, ya que permuta directamente a los elementos.

// shuffle() en listas mutables
fun <T> MutableList<T>.shuffle()
fun <T> MutableList<T>.shuffle(random: Random)

// shuffle() en arreglos
fun <T> Array<T>.shuffle()
fun <T> Array<T>.shuffle(random: Random)

Tomemos como ejemplo un diseño sencillo de una baraja francesa con sus 52 naipes. La idea es hacer uso de la función shuffle() para barajar las cartas y mostrar el orden aleatorio generado.

La clase que representa el palo y los rangos de cada carta es la siguiente:

import Card.Rank
import Card.Suite

class Card(private val suite: Suite, private val rank: Rank) {
    enum class Suite(val symbol: Char) {
        CLUB('♣'),
        DIAMOND('♦'),
        HEART('♠'),
        SPADE('♥')
    }

    enum class Rank(val symbol: String) {
        TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"),
        SEVEN("7"), EIGHT("8"), NINE("9"), TEN("10"),
        JACK("J"), QUEEN("Q"), KING("K"), ACE("A")
    }

    override fun toString(): String {
        return "${rank.symbol}${suite.symbol}"
    }
}

La clase Card usa dos enumeraciones para representar a los símbolos usados para las cartas. Esto nos permite sobrescribir el método toString() para generar una vista legible ahora que construyamos el mazo.

Crearemos una arreglo con 52 posiciones y luego construiremos el mazo a través de dos bucles for que recorran tanto palos como rangos (también puedes usar la función forEach()):

fun main() {   
    val deck = arrayOfNulls<Card>(52)

    var deckIndex = 0
    for (s in Suite.values()) {
        for (r in Rank.values()) {
            deck[deckIndex] = Card(s, r)
            deckIndex++
        }
    }

    printDeck(deck)

    deck.shuffle() // Barajar mazo

    println()
    printDeck(deck)
}

private fun printDeck(deck: Array<Card?>) {
    deck.forEachIndexed { index, card ->
        print("$card ")
        if ((index + 1) % 13 == 0) {
            println()
        }
    }
}

Salida:

2♣ 3♣ 4♣ 5♣ 6♣ 7♣ 8♣ 9♣ 10♣ J♣ Q♣ K♣ A♣ 
2♦ 3♦ 4♦ 5♦ 6♦ 7♦ 8♦ 9♦ 10♦ J♦ Q♦ K♦ A♦ 
2♠ 3♠ 4♠ 5♠ 6♠ 7♠ 8♠ 9♠ 10♠ J♠ Q♠ K♠ A♠ 
2♥ 3♥ 4♥ 5♥ 6♥ 7♥ 8♥ 9♥ 10♥ J♥ Q♥ K♥ A♥ 

2♥ 3♣ J♥ 5♥ 4♥ K♥ 4♦ 8♣ 3♠ K♦ J♦ 8♥ 9♥ 
J♣ 4♣ 3♥ K♣ A♠ 7♠ Q♦ 5♠ J♠ 9♦ Q♥ 7♦ 3♦ 
A♣ 8♠ 6♦ 10♣ 9♣ 9♠ Q♣ 6♥ K♠ 10♦ Q♠ 5♦ A♦ 
5♣ 7♣ 2♠ 4♠ 6♠ 2♦ 7♥ 8♦ 10♠ 10♥ 2♣ 6♣ A♥ 

Como ves, hemos creado una función printDeck() para imprimir el mazo en cuatro filas de 13 cartas. Esto nos permite saber el estado antes de y después al barajar el arreglo con shuffle().

De esta forma, los valores son intercambiados entre posiciones en la misma instancia del arreglo a diferencia de shuffled().

Ú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!