Operaciones con colecciones VI: Recuperar elementos

Operaciones con colecciones VI: Recuperar elementos

Continuando con la serie sobre Operaciones con colecciones, en esta entrada veremos que las colecciones en Kotlin también proporcionan un conjunto de funciones para recuperar elementos individuales de las colecciones, lo que se aplica tanto a listas como a los conjuntos, utilizando para ello distintos métodos para referirse a los elementos.

Recuperar elementos por posición

Teniendo en cuenta que las listas son colecciones ordenadas en las que cada elemento tiene una posición que se puede usar para referirse a él, y que un conjunto, aunque no es una colección ordenada, también almacena sus elementos según ciertos criterios de orden como el orden de inserción de cada elemento, el orden de clasificación natural o cualquier otro criterio aunque sea desconocido (en tales casos, los elementos todavía están ordenados de alguna manera, por lo que las funciones que dependen de las posiciones de los elementos aún devuelven resultados válidos aunque impredecibles), existen métodos para recuperar elementos a partir de su posición.

Para recuperar un elemento en una posición específica, existe la función elementAt() que llamamos con un número entero como argumento, y devuelve el elemento de colección en esa posición (recuerda que el primer elemento está en la posición 0 y el último en la posición tamaño - 1).

elementAt() es útil para colecciones que no proporcionan (o que no se sabe que proporcionen) acceso indexado, si bien en el caso de List se suele utilizar el operador de acceso indexado get() o el índice entre [].
fun main() {
    val numeros = linkedSetOf("uno", "dos", "tres", "cuatro", "cinco")
    println(numeros.elementAt(3)) // cuatro

    val numerosOrdenados = sortedSetOf("uno", "dos", "tres", "cuatro")
    println(numerosOrdenados.elementAt(0)) // cuatro

    val numerosLista = listOf(1, 2, 3, 4, 5)
    println(numerosLista.elementAt(2)) // 3
    println(numerosLista.get(2))       // 3
    println(numerosLista[2])           // 3
}

También hay herramientas útiles para recuperar el primer y último elemento de la colección: first() y last():
println(numerosLista.first()) // 1
println(numerosLista.last())  // 5

Para evitar excepciones al recuperar elementos con posiciones no existentes debemos usar variaciones seguras de elementAt() como:
  • elementAtOrNull() que devuelve null cuando la posición especificada está fuera de los límites de la colección.
  • elementAtOrElse() que toma como argumento, además del índice de posición, una función lambda con ese mismo índice, y cuando se llama con una posición fuera de los límites devuelve el resultado de esa lambda.
val numeros = listOf("uno", "dos", "tres", "cuatro", "cinco")
println(numeros.elementAtOrNull(5)) // null
println(numeros.elementAtOrElse(5) { index -> "Valor no definido para el índice $index" })

Recuperar elementos por condición

Las funciones first() y last() también permiten buscar elementos en una colección que coincidan con un predicado determinado. Así, cuando se llama a first() con un predicado que comprueba un elemento de la colección, devuelve el primer elemento en el que el predicado se traduce en verdadero. A su vez, last() con un predicado devuelve el último elemento que coincide con él.
val numeros = listOf("uno", "dos", "tres", "cuatro", "cinco", "seis")
println(numeros.first { it.length > 3 }) // tres
println(numeros.last { it.startsWith("c") }) // cinco

Si ningún elemento coincide con el predicado, ambas funciones lanzan excepciones, y para evitarlo usamos firstOrNull() y lastOrNull() que devuelven null si no encuentran elementos coincidentes.
println(numeros.firstOrNull { it.length > 6 }) // null

Otra alternativa para evitar estas excepciones es usar find() en lugar de firstOrNull() y findLast() en lugar de lastOrNull():
println(numeros.find { it.length > 6 }) // null

Otro ejemplo:
val numeros = listOf(1, 2, 3, 4)
println(numeros.find { it % 2 == 0 }) // 2
println(numeros.findLast { it % 2 == 0 }) // 4

Recuperar elemento aleatorio

Si necesitamos recuperar un elemento arbitrario de una colección, podemos usar la función random() que podemos llamar sin argumentos o con un objeto tipo Random como fuente de la aleatoriedad.
import kotlin.random.Random
import kotlin.random.Random.Default.nextInt

fun main() {
    val numeros = listOf("uno", "dos", "tres", "cuatro", "cinco", "seis")
    println(numeros.random())
    println(numeros.random(Random(nextInt(0, numeros.size))))
}

Comprobar un elemento

Por otra parte, en algunas ocasiones nos puede interesar, en lugar de recuperar un elemento, verificar si ese elemento está presente en la colección, para lo que podemos usar la función contains() que devuelve true si existe un elemento en la colección igual al argumento utilizado en la llamada a la función. También podemos llamar a contains() con la palabra reservada in. Además, para comprobar la presencia de varios argumentos, podemos utilizar containsAll() con una colección de elementos que queremos verificar como argumento.
val numeros = listOf("uno", "dos", "tres", "cuatro", "cinco", "seis")
println(numeros.contains("cuatro")) // true
println("cero" in numeros)          // false

println(numeros.containsAll(listOf("cuatro", "dos"))) // true
println(numeros.containsAll(listOf("uno", "cero")))   // false

También podemos verificar si una colección contiene algún elemento o está vacía con isNotEmpty() y isEmpty():
val numeros = listOf("uno", "dos", "tres", "cuatro", "cinco", "seis")
println(numeros.isEmpty())    // false
println(numeros.isNotEmpty()) // true

val listaVacia = emptyList<String>()
println(listaVacia.isEmpty())    // true
println(listaVacia.isNotEmpty()) // false

Comentarios

Entradas populares

Recursos gratis para aprender Kotlin

I/O: entrada y salida de datos en consola

Lectura y escritura de archivos