Los hash-sets son colecciones mutables y desordenadas que almacenan cada valor como máximo una vez. La búsqueda, la inserción y la eliminación son todas O(1) en promedio. Viven en hash-sets e implementan el protocolo de sets.
HS{ "NS-1024" "WB-203" } .
! => HS{ "NS-1024" "WB-203" }
HS{ } es el literal vacío. Como otros literales de Factor, es un objeto compartido: cada referencia a HS{ } en el código fuente apunta al mismo conjunto. HS{ } clone te da una copia nueva e independiente en cada llamada.
>hash-set ( seq -- set ) ! build a fresh set from a sequence
Cuando ya tienes los valores en una secuencia, >hash-set los convierte en un solo paso y descarta los duplicados.
USING: hash-sets prettyprint ;
{ "NS-1024" "WB-203" "NS-1024" } >hash-set .
! => HS{ "NS-1024" "WB-203" }
adjoin ( elt set -- ) ! insert in place; no-op if already present
adjoin-all ( seq set -- ) ! insert every element of seq in place
delete ( elt set -- ) ! remove in place; no-op if absent
Los tres modifican el conjunto; ninguno devuelve nada en la pila.
USING: hash-sets kernel sets ;
HS{ } clone
"NS-1024" over adjoin
"WB-203" over adjoin
"NS-1024" over adjoin ! duplicate — no effect
. ! => HS{ "NS-1024" "WB-203" }
adjoin-all es la forma masiva: agrega cada elemento de una secuencia y omite los duplicados, igual que adjoin lo hace uno a la vez.
USING: hash-sets kernel sets ;
HS{ "NS-1024" } clone
{ "WB-203" "NS-1024" "QR-7" } over adjoin-all
. ! => HS{ "QR-7" "NS-1024" "WB-203" } (order not guaranteed)
in? ( elt set -- ? ) ! is elt in the set?
null? ( set -- ? ) ! is the set empty?
cardinality ( set -- n ) ! number of elements
members ( set -- seq ) ! enumerate as a sequence
in? es la prueba de pertenencia del protocolo de conjuntos. Es distinto de member? (de sequences), que hace un recorrido lineal sobre una secuencia. Para un hash-set, in? es una búsqueda hash, O(1) en promedio, que es el punto central de usar un hash-set.
null? informa si el conjunto no tiene elementos: la forma directa de preguntar «¿está vacío?» en lugar de comparar cardinality con cero.
: my-log ( -- set ) HS{ "NS-1024" "WB-203" } ;
"NS-1024" my-log in? . ! => t
"X-99" my-log in? . ! => f
my-log null? . ! => f
HS{ } clone null? . ! => t
my-log cardinality . ! => 2
union ( set1 set2 -- set )
intersect ( set1 set2 -- set )
diff ( set1 set2 -- set )
set-like ( set exemplar -- set' )
union es «todos los elementos de cualquiera de los dos»; intersect es «elementos en ambos»; diff es «en set1 pero no en set2». Cada uno devuelve un conjunto nuevo sin modificar los conjuntos originales.
set-like convierte set al tipo de exemplar. Las implementaciones predeterminadas de union/intersect/diff lo usan para que el resultado coincida con el tipo del receptor: <my-set> <hash-set> union devuelve un my-set, no un hash-set.
Los hash-sets se combinan de forma natural con las tablas hash para el recorrido de grafos: una tabla hash asigna cada nodo a sus vecinos, y un hash-set registra qué nodos ya se visitaron para que la búsqueda no entre en bucle ni repita trabajo. El recorrido es entonces una cola más las dos estructuras, que se modifican en el lugar a medida que avanzas hacia afuera.
Eres el farero del faro de Cape Crozier. Desde la sala de la linterna registras cada embarcación que pasa (cada una se identifica con una señal de llamada única) y además coordinas las retransmisiones de señales con los demás faros a lo largo de la costa.
Define empty-log para que devuelva un conjunto hash nuevo y vacío,
listo para ir acumulando señales de llamada.
empty-log .
! => HS{ }
Define sight para que reciba una bitácora y una señal de llamada, y
registre el avistamiento en el lugar. No devuelve nada.
empty-log dup "NS-1024" sight .
! => HS{ "NS-1024" }
Define seen? para que reciba una bitácora y una señal de llamada, y
devuelva t si la señal de llamada ya está registrada y f en caso
contrario.
HS{ "NS-1024" "WB-203" } "NS-1024" seen? . ! => t
HS{ "NS-1024" "WB-203" } "X-99" seen? . ! => f
Define forget-sighting para que reciba una bitácora y una señal de
llamada, y elimine la señal de llamada de la bitácora en el lugar. No
devuelve nada. Si la señal de llamada no está, no hagas nada.
HS{ "NS-1024" "WB-203" } clone dup "WB-203" forget-sighting .
! => HS{ "NS-1024" }
Define unique-count para que devuelva la cantidad de señales de
llamada distintas que hay en la bitácora.
HS{ "NS-1024" "WB-203" "AC-77" } unique-count . ! => 3
empty-log unique-count . ! => 0
La guardia costera mantiene un relay-map: una tabla hash cuyas claves
son nombres de faros, y cada valor es un array con los faros a los que
el faro de la clave puede retransmitir directamente.
Define reachable para que reciba un faro start y un relay-map, y
devuelva un conjunto hash con todos los faros a los que se puede llegar
desde start (incluido el propio start) mediante retransmisiones
sucesivas.
H{
{ "Crozier" { "Beacon" "Hadley" } }
{ "Beacon" { "Crozier" "Spiral" } }
{ "Hadley" { "Crozier" } }
{ "Spiral" { "Beacon" "Outpost" } }
{ "Outpost" { "Spiral" } }
{ "Far-Isle" { "Lonely" } }
{ "Lonely" { "Far-Isle" } }
}
"Crozier" swap reachable .
! => HS{ "Crozier" "Beacon" "Hadley" "Spiral" "Outpost" }
El par Far-Isle/Lonely forma su propia componente conexa, así que
ninguno de los dos aparece en el resultado.
Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.