En este tutorial verás la definición y uso de mapas en Kotlin. Verás la declaración de la interfaz Map
, como crear mapas de solo lectura, mapas mutables y como iterar sobre sus entradas en un bucle for.
Mapas
Un mapa es una colección que almacena sus elementos (entradas) en forma de pares clave-valor.
Esto quiere decir que a cada clave le corresponde un solo valor y será única como si se tratase de un identificador.
La ilustración anterior muestra la correspondencia entre una colección de claves a una de valores. Por ejemplo, la entrada «Name» -> «Catrina sería un habitante del mapa.
Crear Mapas De Solo Lectura
La interfaz que representa a los mapas en Kotlin es Map<K,V>
. Donde los parámetros de tipo K
y V
representan a los tipos para claves (propiedad keys
) y valores (propiedad values
).
interface Map<K, out V>
Esta definición solo te provee acceso de solo lectura, por lo que solo podrás usar comportamientos de consulta.
Para crear un mapa de solo lectura usa una de las formas de la función mapOf()
:
// Múltiples pares
fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V>
// Mapa vacío
fun <K, V> mapOf(): Map<K, V>
// Un solo par
fun <K, V> mapOf(pair: Pair<K, V>): Map<K, V>
Como ves, las entradas del mapa se generan con la clase Pair
, la cual representa un par de valores genérico.
Por ejemplo, si creas un mapa para cargar los ajustes de un usuario en tu aplicación:
fun main() {
val userSettings: Map<String, String> = mapOf(
"name" to "Catrina",
"language" to "Español",
"logo" to "logo.png",
"website" to "www.site.com"
)
println("$userSettings")
// {name=Catrina, language=Español, logo=logo.png, website=www.site.com}
}
La función de extensión to()
usa el modificador infix para permitirte crear pares de forma legible:
infix fun <A, B> A.to(that: B): Pair<A, B>
Sin embargo, también es posible crear el par con el constructor de la forma Pair("name", "Catrina")
.
Operaciones De Lectura
Los siguientes son atributos y métodos que te permiten consultar el estado de tus mapas:
entries
: retorna un tipoSet<Entry<K,V>>
de solo lectura de todos los pares clave-valorkeys
: retorna unSet<K>
de solo lectura de todas las clavessize
: retorna el número de entradas en el mapavalues
: retornar unaCollection<V>
de solo lectura con los valores en el mapa
Si imprimes todas las propiedades del ejemplo anterior tendrás lo siguiente:
println(userSettings.size) // 4
println(userSettings.entries) // [name=Catrina, language=Español, logo=logo.png, website=www.site.com]
println(userSettings.keys) // [name, language, logo, website]
println(userSettings.values) // [Catrina, Español, logo.png, www.site.com]
Por el lado de los métodos de lectura tienes a:
mapa[clave]
: Esta sintaxis permite obtener el valor a partir de la clave en el corchete. Es la construcción equivalente al operadorget(clave)
getOrDefault(key, defaultValue)
: Obtiene el valor correspondiente a la clave, de lo contrario retorna adefaultValue
isEmpty()
: Retornatrue
si el mapa no contiene entradas yfalse
en caso contrariocontainsKey(key)
: Retornatrue
sikey
existe en el mapa. Esto es equivalente a usar el operadorin
al comprar la clave frente al mapacontainsValue(value)
: Retornatrue
si una o varias claves se relacionan convalue
Observa algunos ejemplos:
println(userSettings["logo"]) // logo.png
println(userSettings.get("web")) // null
println(userSettings.getOrDefault("email", "Sin email")) // Sin email
println(userSettings.isEmpty()) // false
println("name" in userSettings) // true
println("Español" in userSettings.values ) // true
El tipo de retorno del operador get()
es anulable, por lo que si no encuentra el elemento obtendrás null
como se muestra en la línea 2.
Tanto containsKey()
como containsValue()
pueden reemplazarse con el operador in
.
Crear Mapas Mutables
Los mapas mutables te otorgan el poder de usar comandos de operaciones sobre los elementos como agregar, actualizar y remover entradas. El diseño de esta figura la encuentras en la interfaz MutableMap<K,V>
, la cual extiende de Map<K,V>
.
interface MutableMap<K, V> : Map<K, V>
Crea una instancia de un mapa mutable con el método mutableMapOf()
. Al igual que mapOf()
recibe argumentos variables para los pares iniciales, o puedes crear una definición vacía:
fun <K, V> mutableMapOf(): MutableMap<K, V>
fun <K, V> mutableMapOf(
vararg pairs: Pair<K, V>
): MutableMap<K, V>
Por ejemplo, creemos un mapa que contenga el año de publicación de varios libros:
fun main() {
val booksMap = mutableMapOf(
"Sinsajo" to 2010,
"Yo, Robot" to 1950,
"Crimen y castigo" to 1935,
"Cien años de soledad" to 1991
)
println(booksMap)
// {Sinsajo=2010, Yo, Robot=1950, Crimen y castigo=1935, Cien años de soledad=1991}
}
Veamos como modificar su estructura.
Añadir Y Actualizar Entradas
Usa el método put(key, value)
para asociar la clave key
con el valor value
. Si la clave no existe la entrada es añadida al mapa, de lo contrario el valor es actualizado.
booksMap.put("La máquina del tiempo", 1890)
booksMap["La máquina del tiempo"] = 1895
println(booksMap)
// {Sinsajo=2010, Yo, Robot=1950, Crimen y castigo=1935, Cien años de soledad=1991, La máquina del tiempo=1895}
Sin embargo IntelliJ IDEA te recomendará usar al operador [ ]
junto con la clave para añadir o actualizar.
Remover Entradas
En este caso usa el método remove(key)
para remover la entrada del mapa. Por ejemplo, eliminemos la entrada para "Sinsajo"
:
booksMap.remove("Sinsajo")
println(booksMap)
// {Yo, Robot=1950, Crimen y castigo=1935, Cien años de soledad=1991, La máquina del tiempo=1895}
Otra variante del método es remove(key, value)
donde se remueve el elemento con la clave key
solo si su valor actual es value
. El retorno será true
si es eliminado o false
en caso negativo.
println(booksMap.remove("Cien años de soledad", 2015)) // false
Recorrer Un Mapa
Debido a la naturaleza de los mapas en Kotlin, es posible desestructurar las declaraciones que comprometan a sus entradas en valores individuales.
Un ejemplo claro de esto es recorrer sobre los elementos de un mapa en un bucle for:
fun main() {
val operationsMap = mapOf(
"Suma" to '+',
"Resta" to '-',
"Multiplicación" to 'x',
"División" to '÷'
)
for ((operation, symbol) in operationsMap) {
println("$operation -> $symbol")
}
}
Salida:
Suma -> +
Resta -> -
Multiplicación -> x
División -> ÷
Como ves, convertimos a la sintaxis (operation, symbol)
cada entrada de operationsMap
, con el fin de utilizar ambos elementos en el cuerpo del bucle.
Esto también es aplicable para la declaración de lambdas. Es posible expresar como lista de parámetros el par clave-valor. Por ejemplo, si usamos la función forEach()
sobre el mapa para imprimir su contenido:
operationsMap.forEach { (k, v) -> println("$k -> $v") }
Pasamos como sección de parámetros el combinado (k, v)
para que el cuerpo del lambda imprima en cada iteración a la entrada.
Ú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!