Gli hash-set sono collezioni mutabili e non ordinate che memorizzano ogni valore al massimo una volta. La ricerca, l'inserimento e la cancellazione sono tutti O(1) in media. Si trovano in hash-sets e implementano il protocollo sets.
HS{ "NS-1024" "WB-203" } .
! => HS{ "NS-1024" "WB-203" }
HS{ } è il letterale vuoto. Come gli altri letterali di Factor, è un oggetto condiviso: ogni riferimento a HS{ } nel codice sorgente punta allo stesso insieme. HS{ } clone produce una copia nuova e indipendente a ogni chiamata.
>hash-set ( seq -- set ) ! build a fresh set from a sequence
Quando hai già i valori in una sequenza, >hash-set li converte in un solo passaggio, scartando i duplicati.
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
Tutte e tre modificano l'insieme; nessuna restituisce nulla sullo stack.
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 è la versione in blocco: aggiunge ogni elemento di una sequenza, saltando i duplicati proprio come fa adjoin uno alla volta.
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? è il test di appartenenza del protocollo dei set. È diverso da member? (di sequences), che esegue una scansione lineare su una sequenza. Per un hash-set, in? è una ricerca hash: O(1) in media, ed è proprio il motivo per cui si usa un hash-set.
null? indica se l'insieme non ha elementi: è il modo diretto per chiedere «è vuoto?» invece di confrontare cardinality con zero.
: 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 è «tutti gli elementi di entrambi»; intersect è «gli elementi in comune»; diff è «quelli in set1 ma non in set2». Ognuna restituisce un nuovo insieme senza modificare i suoi input.
set-like forza set al tipo di exemplar. Le implementazioni predefinite di union/intersect/diff la usano per far corrispondere il tipo del risultato a quello del ricevente: <my-set> <hash-set> union restituisce un my-set, non un hash-set.
Gli hash-set si abbinano naturalmente alle hashtable per l'attraversamento dei grafi: una hashtable associa ogni nodo ai suoi vicini, e un hash-set tiene traccia di quali nodi sono già stati visitati, così la ricerca non entra in cicli né ripete lavoro. L'attraversamento è quindi una coda più le due strutture, modificate sul posto mentre si procede verso l'esterno.
Sei il guardiano del faro di Cape Crozier. Dalla stanza della lanterna registri ogni nave che passa, ognuna identificata da un nominativo univoco, e coordini anche i relè dei segnali con gli altri fari lungo la costa.
Definisci empty-log in modo che restituisca un hash-set vuoto appena creato, pronto a raccogliere i nominativi.
empty-log .
! => HS{ }
Definisci sight in modo che prenda un registro e un nominativo e registri l'avvistamento sul posto. Non restituisce nulla.
empty-log dup "NS-1024" sight .
! => HS{ "NS-1024" }
Definisci seen? in modo che prenda un registro e un nominativo e restituisca t se il nominativo è stato registrato, altrimenti f.
HS{ "NS-1024" "WB-203" } "NS-1024" seen? . ! => t
HS{ "NS-1024" "WB-203" } "X-99" seen? . ! => f
Definisci forget-sighting in modo che prenda un registro e un nominativo e rimuova il nominativo dal registro sul posto. Non restituisce nulla. Se il nominativo non c'è, non fare nulla.
HS{ "NS-1024" "WB-203" } clone dup "WB-203" forget-sighting .
! => HS{ "NS-1024" }
Definisci unique-count in modo che restituisca il numero di nominativi distinti presenti nel registro.
HS{ "NS-1024" "WB-203" "AC-77" } unique-count . ! => 3
empty-log unique-count . ! => 0
La guardia costiera mantiene una relay-map: una hashtable indicizzata per nome del faro, in cui ogni valore è un array dei fari a cui quello indicato dalla chiave può trasmettere direttamente.
Definisci reachable in modo che prenda un faro start e una relay-map, e restituisca un hash-set di tutti i fari raggiungibili da start (incluso start stesso) tramite ripetuti relè.
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" }
La coppia Far-Isle/Lonely è una sua componente connessa, quindi nessuno dei due compare nel risultato.
Iscriviti a Exercism per imparare e padroneggiare Factor con 47 concetti163 esercizi e il mentoring di persone reali, tutto gratis.