Cuando trabajamos con colecciones en Scala, es fundamental entender la diferencia entre colecciones mutables e inmutables, y cómo podemos manipularlas. En este caso, nos centramos en los sets mutables, que nos permiten modificar directamente sus elementos sin necesidad de crear nuevas copias.
Para empezar a usar sets mutables, lo recomendable es importar el paquete scala.collection.mutable. Esto nos permite crear sets mutables de forma explícita, por ejemplo, usando mutable.Set, lo que ayuda a distinguir claramente cuándo estamos trabajando con una colección mutable frente a una inmutable.
Al crear un set mutable, como uno con los elementos 1, 2 y 3, a simple vista puede parecer igual que un set inmutable, pero la diferencia está en cómo podemos modificarlo. Por ejemplo, podemos agregar un elemento usando el operador +=. Este operador no solo devuelve el set modificado, sino que también altera el set original, de modo que las siguientes veces que accedamos a él, veremos el nuevo elemento incluido.
De forma similar, para agregar varios elementos de otro set, podemos usar el operador ++=, que concatena y modifica el set original como efecto colateral. Esto es importante porque, aunque la variable que contiene el set sea inmutable (es decir, no podemos reasignarla a otro set), el contenido del set mutable sí puede cambiar.
Esta distinción entre la mutabilidad de la colección y la mutabilidad de la variable que la contiene es clave. La variable puede ser inmutable, lo que significa que no podemos cambiar la referencia que tiene, pero el objeto al que apunta puede ser mutable y modificarse internamente.
Para eliminar elementos de un set mutable, contamos con el operador -=, que elimina un elemento del set y modifica el set original. Esto contrasta con el operador -, que devuelve una copia del set sin el elemento indicado, pero no altera el set original.
Una operación especialmente útil en sets mutables es retain. Esta función nos permite filtrar el set manteniendo solo aquellos elementos que cumplen una condición específica, eliminando todos los demás directamente de la colección original. Por ejemplo, si queremos quedarnos solo con los números pares, podemos pasar una función lambda que verifique si cada elemento es divisible por dos. Después de aplicar retain, el set mutable habrá eliminado todos los elementos que no cumplen esta condición.
Es importante notar que retain es una versión mutable del operador filter. Mientras que filter devuelve una nueva colección con los elementos que cumplen la condición sin modificar la original, retain modifica la colección en sí. Esto significa que, aunque el set sea mutable, si usamos filter, la colección original permanece intacta y obtenemos una copia filtrada.
Para ilustrar estas operaciones, podemos ver un ejemplo en Scala:
import scala.collection.mutable
val mset = mutable.Set(1, 2, 3)
// Agregar un elemento
mset += 4 // mset ahora contiene 1, 2, 3, 4
// Agregar varios elementos
mset ++= Set(5, 6) // mset ahora contiene 1, 2, 3, 4, 5, 6
// Eliminar un elemento
mset -= 2 // mset ahora contiene 1, 3, 4, 5, 6
// Retener solo los elementos pares
mset.retain(x => x % 2 == 0) // mset ahora contiene 4, 6
Con estas herramientas, podemos manejar sets mutables de forma eficiente, modificando directamente su contenido según nuestras necesidades, y entendiendo claramente la diferencia entre la mutabilidad de la colección y la de la variable que la contiene. Esto nos da un control más fino sobre cómo gestionamos los datos en nuestras aplicaciones Scala.