Hash-sets são coleções mutáveis e sem ordem que guardam cada valor no máximo uma vez. Busca, inserção e remoção são todas O(1) em média. Elas ficam em hash-sets e implementam o protocolo sets.
HS{ "NS-1024" "WB-203" } .
! => HS{ "NS-1024" "WB-203" }
HS{ } é o literal vazio. Como outros literais de Factor, ele é um objeto compartilhado: toda referência a HS{ } no código-fonte aponta para o mesmo conjunto. HS{ } clone dá a você uma cópia nova e independente a cada chamada.
>hash-set ( seq -- set ) ! build a fresh set from a sequence
Quando você já tem os valores em uma sequência, >hash-set os converte de uma vez só, descartando as duplicatas.
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
As três modificam o conjunto; nenhuma retorna nada na pilha.
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 é a forma em massa: ela adiciona cada elemento de uma sequência, pulando as duplicatas assim como adjoin faz um de cada 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? é o teste de pertencimento do protocolo de conjuntos. Ele é diferente de member? (de sequences), que faz uma busca linear em uma sequência. Para um hash-set, in? é uma busca em hash, O(1) em média, que é justamente o motivo de usar um hash-set.
null? informa se o conjunto não tem elementos: é a forma direta de perguntar "isto está vazio?" em vez de comparar cardinality com 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 é "todos os elementos de qualquer um dos dois"; intersect é "os elementos que estão em ambos"; diff é "os que estão em set1 mas não em set2". Cada uma retorna um novo conjunto sem modificar os conjuntos de entrada.
set-like converte set para o tipo de exemplar. As implementações padrão de union/intersect/diff usam isso para fazer o resultado corresponder ao tipo do receptor: <my-set> <hash-set> union retorna um my-set, não um hash-set.
Hash-sets combinam naturalmente com hashtables para percorrer grafos: uma hashtable mapeia cada nó para seus vizinhos, e um hash-set registra quais nós já foram visitados, para que a busca não entre em loop nem repita trabalho. A travessia é então uma fila mais as duas estruturas, modificadas no lugar conforme você avança para fora.
Você é o faroleiro do farol de Cape Crozier. Da sala da lanterna, você registra cada embarcação que passa (cada uma é identificada por um indicativo de chamada único) e também coordena as retransmissões de sinais com os outros faróis ao longo da costa.
Defina empty-log para retornar um hash-set novo e vazio, pronto para coletar indicativos.
empty-log .
! => HS{ }
Defina sight para receber um diário de bordo e um indicativo, e registrar o avistamento ali mesmo. Não retorna nada.
empty-log dup "NS-1024" sight .
! => HS{ "NS-1024" }
Defina seen? para receber um diário de bordo e um indicativo, retornando t se o indicativo já tiver sido registrado e f caso contrário.
HS{ "NS-1024" "WB-203" } "NS-1024" seen? . ! => t
HS{ "NS-1024" "WB-203" } "X-99" seen? . ! => f
Defina forget-sighting para receber um diário de bordo e um indicativo e remover o indicativo do diário ali mesmo. Não retorna nada. Se o indicativo não estiver no diário, não faça nada.
HS{ "NS-1024" "WB-203" } clone dup "WB-203" forget-sighting .
! => HS{ "NS-1024" }
Defina unique-count para retornar o número de indicativos distintos no diário.
HS{ "NS-1024" "WB-203" "AC-77" } unique-count . ! => 3
empty-log unique-count . ! => 0
A guarda costeira mantém um relay-map: uma hashtable indexada pelo nome do farol, em que cada valor é um array dos faróis para os quais o farol correspondente consegue retransmitir diretamente.
Defina reachable para receber um farol start e um relay-map, e retornar um hash-set de todos os faróis alcançáveis a partir de start (incluindo o próprio start) por retransmissões repetidas.
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" }
O par Far-Isle/Lonely forma seu próprio componente conectado, então nenhum dos dois aparece no resultado.
Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.