Hashes
A Hash is a collection of unique keys and their corresponding values in pairs. In Smojo, the word# ( -- # )creates an empty hash on the stack:
# constant my-hash
my-hash .
{} ok
Here constantbinds the hash created by
#to
my-hash. Therefore, we can get the hash directly by
my-hash. The word
#! ( k v # -- )writes a key-value pair into an existing hash. It requires three arguments: key (k), value (v) and the target hash (#):
"year" 2017 my-hash #!
my-hash .
{year=2017} ok
Both the key and value can be anything -- text and integer ( as in the example above ) or XTs. Anything.
The word #@ ( k # -- v )returns a matching value given its key:
"year" my-hash #@ . 2017 okNote that if the key is not on the hash, the result is a special object called
NULL ( -- null ), which can be tested using the word
NULL? ( * -- f ). For example:
"bingo" my-hash #@ null? . true ok "year" my-hash #@ null? . false okYou may test for the presence of a key-value pair on a hash by using the word
#CONTAINS? ( k # -- f ). This word puts
TRUEon the stack if a key exists on the hash and
FALSEotherwise:
"year" my-hash #contains? . true okThe word
#DROP ( k # -- )removes a key-value pair from the hash; It requires two arguments: key and the target hash table:
"year" my-hash #drop
my-hash .
{} ok
In summary, hashes are a simple data structure in which you can store and retrieve data temporarily (i.e., as long as your program is running.). Here are some other useful words for a hash:
| Word | Action |
|---|---|
#@ ( k # -- v ) |
Retrieves a value (v) from a hash given the corresponding key (k). |
#! ( k v # -- ) |
Stores a key-value pair (k v) into a hash. |
#CONTAINS? ( k # -- f ) |
Returns TRUE if the key (k) is on the hash and FALSE otherwise. |
#KEYS ( # -- seq ) |
Takes a hash and returns the sequence of all keys. Note that the keys are returned in no particular order. |
#VALUES ( # -- seq ) |
Takes a hash and returns the sequence of all values. Note that the values are returned in no particular order. |
#SORTED ( -- # ) |
This puts a special "sorted" hash on the stack.
The #KEYSof a sorted hash will be sorted in "alphabetical" (or more precisely, lexicographical) order. |
># ( #t #s -- ) |
Copies the contents of the source hash (#s) into the target hash (#t). |
#EMPTY? ( # -- f ) |
Returns TRUEif the hash is empty, FALSEotherwise. |
#SIZE ( # -- n ) |
Returns the number of key-value pairs in the hash. |
Quiz
Question 1
Is is possible to haveNULLas key or associated value in a hash? Prove your answer using a program.
# constant h
null "success" h #! \ possible
h . \ {null=success}
Question 2
What happens if a key-value pair is overwritten by the same key but with a different value? Prove your answer using a program.
# constant h
"HI" "original" h #!
h . cr \ {HI=original}
"HI" "overwritten" h #!
h . cr \ {HI=overwritten}
The old value is overwritten by the new value
Question 3
Create a hash called "me" and write your name, age, and gender into the hash. Then try the following words on your hash:
#SIZE \ returns the number of key-value pairs in the hash. #EMPTY? \ returns true if the hash is empty. #CONTAINS? \ returns true if the has contains the given keyContinue with your hash "me", remove all the key-value pairs from hash "me" and then try
#EMPTY?to see if it is empty now.
# constant me
"name" "smojo" me #!
"age" 22 me #!
"gender" "M" me #!
me . cr \ {gender=M, name=smojo, age=22}
"size?" . me #size . cr \ size? 3
"empty?" . me #empty? . cr \ empty? false
"contains name?" . "name" me #contains? . cr \ contains name? true
"contains height?" . "height" me #contains? . cr \ contains height? false
"name" me #drop
"gender" me #drop
"age" me #drop
me . cr \ {}
"empty?" . me #empty? . cr \ empty? true
Question 4*
The words#KEYSand
#VALUESreturn the keys and the values in a hash as a sequence respectively. Write a word
#CLEARwhich removes all the key-value pairs in a hash. Hint: which word can remove key-value pairs from a hash and which word returns the required input for that word?
: #CLEAR ( # -- # ) begin dup dup #keys head swap #drop dup #empty? until ;
Question 5*
Can a hash be used as a value in a hash? When might this be useful? Hint: how would you store the details of each student (name, height, gender) in a class to be retrieved by that student's ID?
\ hashes can be used as both key and value
# constant h
# constant h1
# constant h2
h1 h2 h #!
h . cr \ {{}={}}
\ each student info can be stored in a hash
\ each hash is retrievable by student ID
\ keys: student ID ; values: hashes of student
# constant students
\ keys: name, height, gender ; values: corresponding values
# constant s1
# constant s2
"name" "Ana" s1 #!
"height" 160 s1 #!
"gender" "F" s1 #!
"name" "Dave" s2 #!
"height" 180 s2 #!
"gender" "M" s2 #!
1155001 s1 students #!
1155002 s2 students #!
students . cr
\ {1155001={gender=F, name=Ana, height=160},
\ 1155002={gender=M, name=Dave, height=180}}
