«مجموعهی هش» گونهای مجموعهی تغییرپذیر و بدون ترتیب است که هر مقدار را حداکثر یک بار ذخیره میکند. جستوجو، درج و حذف همگی بهطور میانگین O(1) هستند. اینها در hash-sets قرار دارند و پروتکل sets را پیادهسازی میکنند.
HS{ "NS-1024" "WB-203" } .
! => HS{ "NS-1024" "WB-203" }
HS{ } لیترال خالی است. مثل دیگر لیترالهای Factor، یک شیء مشترک است: هر ارجاعی به HS{ } در کد منبع به همان مجموعه اشاره میکند. HS{ } clone در هر فراخوانی یک نسخهی تازه و مستقل به شما میدهد.
>hash-set ( seq -- set ) ! build a fresh set from a sequence
وقتی مقادیر را از قبل در یک دنباله دارید، >hash-set آنها را در یک مرحله تبدیل میکند و از تکراریها صرفنظر میکند.
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
هر سه، مجموعه را تغییر میدهند و هیچکدام چیزی روی پشته برنمیگرداند.
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 شکل گروهی است: هر عنصر یک دنباله را میافزاید و از تکراریها هم درست مثل adjoin که یکییکی این کار را میکند، صرفنظر میکند.
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? آزمون عضویت پروتکل مجموعه است. با member? (از sequences) فرق دارد؛ آن یکی یک پویش خطی روی دنباله انجام میدهد. برای یک مجموعهی هش، in? یک جستوجوی هش است، بهطور میانگین O(1)، و همین تمام دلیل استفاده از مجموعهی هش است.
null? گزارش میدهد که آیا مجموعه هیچ عنصری دارد یا نه؛ راه مستقیم برای پرسیدن «آیا این خالی است؟» بهجای مقایسهی cardinality با صفر.
: 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 یعنی «همهی عناصری که در هر کدام از دو مجموعه هستند»؛ intersect یعنی «عناصری که در هر دو هستند»؛ diff یعنی «عناصری که در set1 هستند اما در set2 نیستند». هر کدام یک مجموعهی جدید برمیگرداند و ورودیهایش را تغییر نمیدهد.
set-like نوع set را به نوع exemplar تبدیل میکند. پیادهسازیهای پیشفرض union/intersect/diff از آن استفاده میکنند تا نوع نتیجه با نوع گیرنده همخوان شود؛ <my-set> <hash-set> union یک my-set برمیگرداند، نه یک مجموعهی هش.
مجموعهی هش بهطور طبیعی برای پیمایش گراف در کنار جدول هش به کار میآید: جدول هش هر گره را به همسایههایش نگاشت میکند و مجموعهی هش ثبت میکند کدام گرهها قبلاً بازدید شدهاند تا جستوجو به حلقه نیفتد یا کاری را دوباره انجام ندهد. آنگاه پیمایش چیزی نیست جز یک صف بههمراه این دو ساختار که همانجا، در حین گسترش به بیرون، تغییر میکنند.
شما نگهبان فانوس دریایی کیپ کروزیر هستید. از اتاق فانوس، هر شناوری را که از آنجا میگذرد ثبت میکنید و هر شناور با یک «نشانهی تماس» یکتا شناسایی میشود. همچنین رلههای سیگنال را با فانوسهای دریایی دیگر در سراسر ساحل هماهنگ میکنید.
empty-log را طوری تعریف کنید که یک hash-set خالی و تازه برگرداند، آماده برای جمعآوری نشانههای تماس.
empty-log .
! => HS{ }
sight را طوری تعریف کنید که یک دفتر ثبت و یک نشانهی تماس بگیرد و مشاهده را بهصورت درجا ثبت کند. چیزی برنمیگرداند.
empty-log dup "NS-1024" sight .
! => HS{ "NS-1024" }
seen? را طوری تعریف کنید که یک دفتر ثبت و یک نشانهی تماس بگیرد و اگر نشانهی تماس ثبت شده باشد t و در غیر این صورت f برگرداند.
HS{ "NS-1024" "WB-203" } "NS-1024" seen? . ! => t
HS{ "NS-1024" "WB-203" } "X-99" seen? . ! => f
forget-sighting را طوری تعریف کنید که یک دفتر ثبت و یک نشانهی تماس بگیرد و نشانهی تماس را بهصورت درجا از دفتر حذف کند. چیزی برنمیگرداند. اگر نشانهی تماس در دفتر نباشد، هیچ کاری نکنید.
HS{ "NS-1024" "WB-203" } clone dup "WB-203" forget-sighting .
! => HS{ "NS-1024" }
unique-count را طوری تعریف کنید که تعداد نشانههای تماس متمایز در دفتر را برگرداند.
HS{ "NS-1024" "WB-203" "AC-77" } unique-count . ! => 3
empty-log unique-count . ! => 0
گارد ساحلی یک relay-map نگه میدارد: یک hashtable که کلیدش اسم فانوس دریایی است و هر مقدار آن آرایهای است از فانوسهای دریایی که فانوس متناظر با کلید میتواند مستقیماً به آنها رله کند.
reachable را طوری تعریف کنید که یک فانوس دریایی start و یک relay-map بگیرد و یک hash-set از همهی فانوسهای دریایی برگرداند که از start با رلههای پشتسرهم قابل دسترساند (شامل خود start هم میشود).
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" }
جفت Far-Isle/Lonely مؤلفهی همبند جداگانهی خودش است، پس هیچکدام در نتیجه ظاهر نمیشوند.