Kotlin - Set

Introducció

Un conjunt és una col·lecció que no té un ordre específic i no permet valors duplicats. Com és possible una col·lecció així? El secret és el codi hash.

Un codi hash és un Int produït pel mètode hashCode() de qualsevol classe de Kotlin. Es pot considerar com un identificador semi-únic per a un objecte de Kotlin.

Un petit canvi a l’objecte, com afegir un caràcter a una String, dona com a resultat un valor hash molt diferent.

require("Tortuga".hashCode() == 527586514)
require("tortuga".hashCode() == -1137066766)

Tot i que és possible que dos objectes tinguin el mateix codi hash (anomenat col·lisió de hash), la funció hashCode() garanteix un cert grau d’unicitat: la major part del temps, dos valors diferents tenen cadascun un codi hash únic.

A set uses hash codes as array indices.
012345
Tortuga

L’array extern — els números emmarcats en blau — corresponen cadascun a un rang (també conegut com a “cubell”) de possibles codis hash.

Cada llista interna — ombrejada en verd a la dreta — representa els ítems individuals del conjunt.

Com que les col·lisions de hash són relativament poc freqüents, fins i tot quan els índexs potencials són limitats, les llistes internes a cada índex de l’array només tindran un o dos elements cadascuna, tret que s’hi afegeixin desenes o centenars de milers d’elements.

Els conjunts tenen dues propietats importants:

  • Cercar un element específic en un conjunt és ràpid — en comparació amb les llistes — especialment per a col·leccions grans. Mentre que indexOf() d’una List requereix comprovar cada element des del principi fins que es trobi una coincidència, de mitjana, es triga el mateix a comprovar si un element és en un conjunt, sigui el primer element o el número cent mil.

  • Els conjunts tendeixen a utilitzar més memòria que les llistes per a la mateixa quantitat de dades, ja que sovint calen més índexs d’array que dades hi ha al conjunt.

El benefici dels conjunts és garantir la unicitat.

Si estas escrivint un programa per fer el seguiment dels usuaris connectats, un conjunt proporciona una manera simple de comprovar si un usuari ja s’ha connectat. Amb grans quantitats de dades, això sovint és preferible a comprovar si un element existeix en una llista, cosa que requereix iterar per tots els elements.

Com List i MutableList, hi ha tant Set com MutableSet. MutableSet implementa Set, de manera que qualsevol classe que implementi MutableSet ha d’implementar ambdues.

MutableSet

Farem servir un MutableSet per demostrar com afegir i eliminar elements.

Com List, Set té un mètode add().

Els elements dels conjunts no tenen necessàriament un ordre, així que no hi ha índex!

val animals = mutableSetOf("cat", "dog", "bird")

require(!animals.add("cat"))
require(animals.size == 3)

require(animals.add("zebra"))
require(animals.size == 4)

require(!animals.add("zebra"))
require(animals.size == 4)

La funció contains() pren un únic paràmetre i comprova si l’element especificat és dins del conjunt. Si ho és, retorna true. En cas contrari, retorna false.

val animals = mutableSetOf("cat", "dog", "bird")

require(animals.contains("cat"))
require(!animals.contains("fish"))

Alternativament, pots usar l’operador in per comprovar si un element és en una col·lecció:

val animals = mutableSetOf("cat", "dog", "bird")

require("cat" in animals)
require("fish" !in animals)

La funció remove() pren un únic paràmetre i elimina l’element especificat del conjunt:

require("cat" in animals)
animals.remove("cat")
require("cat" !in animals)