Saltar a contenido

A2 · Ejercicios de genéricos

Practica funciones y clases genéricas, restricciones y una colección propia. Cada ejercicio indica la salida esperada.

Ejercicio A2.1

El último, si lo hay. Escribe una función genérica ultimo que reciba una lista de cualquier tipo y devuelva su último elemento, o «nada» si la lista está vacía (usa el mecanismo del lenguaje para un valor que puede faltar).

Pruébala con [1, 2, 3], con [a, b] y con una lista de enteros vacía. Cuando falte el valor, imprime la palabra nada.

Salida esperada:

ultimo de [1, 2, 3]: 3
ultimo de [a, b]: b
ultimo de []: nada

En Kotlin

T? es un valor que puede faltar; lastOrNull() y el operador ?: te ahorran el if.

Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

fun <T> ultimo(lista: List<T>): T? = lista.lastOrNull()
fun main() {
    println("ultimo de [1, 2, 3]: ${ultimo(listOf(1, 2, 3)) ?: "nada"}")
    println("ultimo de [a, b]: ${ultimo(listOf("a", "b")) ?: "nada"}")
    println("ultimo de []: ${ultimo(emptyList<Int>()) ?: "nada"}")
// ... (resto de la solución bloqueado)

Ejercicio A2.2

Un par que se da la vuelta. Crea una clase genérica Par<A, B> con dos valores, primero y segundo, y un método intercambiar() que devuelva otro par con los valores cambiados de sitio (un Par<B, A>). Haz que se escriba como (primero, segundo).

Crea el par (1, uno) y muestra el original y el intercambiado.

Salida esperada:

(1, uno)
(uno, 1)
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

data class Par<A, B>(val primero: A, val segundo: B) {
    fun intercambiar() = Par(segundo, primero)
    override fun toString() = "($primero, $segundo)"
}
fun main() {
// ... (resto de la solución bloqueado)

Ejercicio A2.3

El mínimo de cualquier cosa comparable. Escribe una función genérica minimo que devuelva el menor elemento de una lista, aceptando solo tipos que se puedan comparar entre sí.

Pruébala con [4, 1, 7] y con [pera, casa, uva].

Salida esperada:

1
casa

En Kotlin

Restringe con T : Comparable<T>: así puedes usar < entre dos T.

Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

fun <T : Comparable<T>> minimo(lista: List<T>): T = lista.reduce { a, b -> if (b < a) b else a }
fun main() {
    println(minimo(listOf(4, 1, 7)))
    println(minimo(listOf("pera", "casa", "uva")))
}
// ... (resto de la solución bloqueado)

Ejercicio A2.4

Invertir con una pila. Escribe tu propia clase genérica Pila<T> (apilar, desapilar y saber si está vacía) y úsala para escribir invertir, una función genérica que devuelva la lista al revés: apila todos los elementos y desapílalos uno a uno.

Muestra [1, 2, 3] y [a, b, c] invertidas, cada una en su línea, con los elementos separados por coma y espacio.

Salida esperada:

3, 2, 1
c, b, a
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

class Pila<T> {
    private val elementos = mutableListOf<T>()
    fun apilar(x: T) {
        elementos.add(x)
    }
// ... (resto de la solución bloqueado)

Ejercicio A2.5

Contar con un criterio. Escribe una función genérica contarSi que reciba una lista y una función que decide si un elemento cumple una condición, y devuelva cuántos la cumplen.

Úsala para contar los números pares de 1 a 10, y las palabras de más de 3 letras en [sol, luna, mar, estrella].

Salida esperada:

5
2
Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

fun <T> contarSi(lista: List<T>, cumple: (T) -> Boolean): Int {
    var cuenta = 0
    for (x in lista) {
        if (cumple(x)) cuenta++
    }
// ... (resto de la solución bloqueado)

Ejercicio A2.6

Una caché genérica. Crea una clase genérica Cache<K, V> con un método obtener(clave, calcular): si ya conoce el resultado de esa clave, lo devuelve sin calcularlo otra vez; si no, ejecuta la función calcular, lo guarda y lo devuelve.

Pruébala con una función que imprime calculando N y devuelve N al cuadrado: pide el 4, otra vez el 4, y luego el 5. Comprueba que calculando 4 aparece una sola vez.

Salida esperada:

calculando 4
16
16
calculando 5
25

En Kotlin

MutableMap.getOrPut(clave) { ... } solo ejecuta el bloque si la clave no existe.

Solución modelo (bloqueada)

🔒 La solución completa está bloqueada. Esto es solo un ejemplo de cómo empieza:

class Cache<K, V> {
    private val guardado = mutableMapOf<K, V>()
    fun obtener(clave: K, calcular: (K) -> V): V = guardado.getOrPut(clave) { calcular(clave) }
}
fun main() {
// ... (resto de la solución bloqueado)