Tuplas¶
Las tuplas son colecciones de tamaño fijo que agrupan elementos de tipos posiblemente diferentes. Son útiles para retornar múltiples valores desde una función sin necesidad de definir una clase o estructura específica.
Ejemplo básico:
scala> val x = (50,30)
val x: (Int, Int) = (50,30)
scala> x
val res2: (Int, Int) = (50,30)
// También se pueden crear usando el constructor TupleN
scala> val y = scala.Tuple2(50,30)
val y: (Int, Int) = (50,30)
// Desestructuración de tuplas (pattern matching)
scala> val (x1,x2) = x
val x1: Int = 50
val x2: Int = 30
Acceso a elementos de una tupla¶
Los elementos de una tupla se acceden mediante los métodos ._1, ._2, etc., donde el índice comienza en 1:
scala> val tupla = (1,2,3,4)
val tupla: (Int, Int, Int, Int) = (1,2,3,4)
scala> tupla._1
val res9: Int = 1
scala> tupla._2
val res10: Int = 2
scala> tupla._3
val res11: Int = 3
scala> tupla._4
val res12: Int = 4
// Alternativamente, se puede usar desestructuración
scala> val (a,b,c,d) = tupla
val a: Int = 1
val b: Int = 2
val c: Int = 3
val d: Int = 4
El reconocimiento de patrones con tuplas se realiza mediante la sintaxis (e1,e2,e3,...,en) = tupla, permitiendo agrupar y desagrupar datos de manera eficiente.
Reconocimiento de patrones con tuplas¶
Las tuplas permiten agrupar patrones de entrada para evitar match anidados, mejorando la legibilidad del código.
En lugar de:
exp1 match {
case patron1 => exp2 match {....}
case patron2 => exp2 match {....}
case ...
case patronn => exp2 match {....}
}
Podemos escribir:
(exp1,exp2) match {
case (patron1, ....) => ...
case (patron2, ....) => ...
case ...
case (patronn, ....) => ...
}
Ejemplo: Producto punto entre dos listas¶
El producto punto (o producto escalar) de dos listas se calcula sumando los productos de los elementos correspondientes.
/*
Ejemplo: List(1,2,3) • List(4,5,6) = 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
*/
def productoPunto(l1: List[Int], l2: List[Int]): Int = {
(l1, l2) match {
case (Nil, Nil) => 0 // Ambas listas vacías, producto punto es 0
case (Nil, _) => throw new Exception("l2 es más grande que l1") // l1 vacía pero l2 no
case (_, Nil) => throw new Exception("l1 es más grande que l2") // l2 vacía pero l1 no
case (x :: xs, y :: ys) => x * y + productoPunto(xs, ys) // Caso recursivo
}
}
// Versión con recursividad de cola (tail recursion) para evitar desbordamiento de pila
def productoPuntoCola(l1: List[Int], l2: List[Int]): Int = {
@scala.annotation.tailrec // Anotación que verifica que la recursión sea de cola
def productoPunto(l1: List[Int], l2: List[Int], acc: Int = 0): Int = {
(l1, l2) match {
case (Nil, Nil) => acc // Ambas vacías, retorna el acumulador
case (Nil, _) => throw new Exception("l2 es más grande que l1")
case (_, Nil) => throw new Exception("l1 es más grande que l2")
case (x :: xs, y :: ys) => productoPunto(xs, ys, acc + x * y) // Actualiza acumulador
}
}
productoPunto(l1, l2) // Llama a la función auxiliar con acumulador inicial 0
}
Tabla de resumen¶
| Concepto | Descripción | Ejemplo |
|---|---|---|
| Definición | Colección de tamaño fijo que agrupa elementos de tipos posiblemente diferentes | val t = (1, "hola", true) |
| Acceso por índice | Se accede a elementos con ._1, ._2, ... (índice comienza en 1) |
t._1 retorna 1 |
| Desestructuración | Asignación de elementos de tupla a variables individuales | val (a, b, c) = t |
| Pattern matching con tuplas | Permite coincidir patrones sobre múltiples valores simultáneamente | (x, y) match { case (0, 0) => ... } |
| Producto punto | Operación que multiplica elementos correspondientes de dos secuencias y suma los resultados | List(1,2,3) • List(4,5,6) = 32 |
| Recursividad de cola | Forma de recursión donde la llamada recursiva es la última operación, optimizable por el compilador | Función productoPuntoCola |
Comentarios adicionales¶
- Inmutabilidad: Las tuplas en Scala son inmutables, una vez creadas no pueden modificarse.
- Límite de tamaño: Scala soporta tuplas hasta Tuple22 (22 elementos), suficiente para la mayoría de casos prácticos.
- Uso común: Se utilizan frecuentemente para retornar múltiples valores de funciones, especialmente cuando los valores son de tipos diferentes.
- Alternativas: Para agrupaciones más complejas o con semántica específica, es preferible usar case classes en lugar de tuplas.
- Errores en tiempo de compilación: El acceso con índice incorrecto (ej:
._5en una tupla de 4 elementos) se detecta en tiempo de compilación. - Interoperabilidad: Las tuplas son especialmente útiles para interoperar con APIs Java que retornan múltiples valores.