Hash Table

Purpose

Provides a hash table, which maps string keys to values.

Syntax

Dim ht As Hash Type

ht: varname
Type: simple type

Description

A Hash is a one dimensioned 'array' and its index is a string. A Hash table has no size, just a number of elements. For Example, with Dim ht As Hash Int declares a dynamic table (array) ht of type Int, which has initially no elements.

Type specifies the data type of the values to be stored in the hash table. Type may be Byte, Boolean, Card, Short, Word, Integer, Long, Large, Currency, Single, Double, Date, String (variable-length strings only) and Variant.

A hash table supports the creation, storage, and retrieval of key/value pairs in memory. The hash table maps string keys to values; the index for hash tables is a case-insensitive string. When the type of the hash table is String, the hash table acts as a dictionary (string/string pair).

After declaring a hash, you can add elements of appropriate type to it, in one of two ways:

Hash Add ht["key"], value

ht["key"] = value

A Hash uses brackets to access an element. To access an element stored in a hash table, you simply specify the key.

value = ht["key"]

To obtain the number of elements of the hash table you use % as the key:

number_of_elements = ht[ % ]

To inquire if an element exists in the table prefix the key with a question mark:

If Not ht[? "key"] Then Hash Add ht["key"], value

A key cannot be duplicated, is case-insensitive and all keys must be unique. When you add a value with an already existing key, the value isn't added and an error is generated.

If you wish to use case-sensitive keys, this is possible by using a basic String to Hex conversion function as shown below:

Trace StrToHex("Hello")

Trace StrToHex("HELLO")

Debug.Show

 

Function StrToHex(s As String) As String

// Acknowledgements to (X) on GB32 Forum

Dim h As String, i

h = ""

For i = 1 To Len(s)

h = h & Hex(Asc(Mid(s, i, 1)))

Next i

StrToHex = h

End Function

Internally, the Hash is implemented as a double linked list. Each element has its own position (index) in the list. Therefore, a hash table can be accessed as if it were an array using a number as the index starting at 1. To mark a key as numeric value, rather than a string, precede the numeric value with %.

value = ht[% 1]

In the same way you can iterate over a hash table using For Next:

For i = 1 To ht[ % ]

Print ht[ % i]

Next

Another way to iterate over a hash table is by using For Each element In hashvar.

Dim e As Int  // same type as Hash <type>

For Each e In ht[]

Print "Element = "; e; " at position "; Each; " and Key = "; ht[$ Each]

Next

The variable e receives the value from that position and must be of the same type as the type of the Hash. Each returns the current position (index) in the hash table.

A hash table can also store values without a key. The Hash is reduced to a double linked list, what it basically is. The only way to add key-less elements to the list is by using Hash Add. An advantage of Hash Add is that it gives control on the position of the elements.

Hash Add ht[], value

Hash Add ht[] Before idx, value

Hash Add ht[] After idx, value

To iterate over the list you can use For Next or For Each. The list variant of the hash table is used in quite some GFA-BASIC 32 commands like Split, Join, Eval, reSub, reMatch.

To remove an element use Hash Remove ht[ "key" | % index]

A hash table can be sorted by its keys, saved, loaded, and erased. The following commands are available:

Hash Erase Deletes the entire hash table.
Hash Sort Sort the hash table by its keys using the Mode Compare setting.
Hash Write Save a hash table as an ASCII file.
Hash Input Load a hash table from an ASCII file.
Hash Save Save a hash table in binary format.
Hash Load Load a hash table in binary format.

Other operations on a hash table are performed using the subscription notation [ ].

Subscript Meaning
[ % ] returns the number of elements
[ % i ] accesses the element by index i (position)
[ k$ ] accesses the element by key k$ (string)
[ $ i ] returns the key for the given index i.
[ ? k$ ] returns a Boolean indicating whether the key k$ exists.
[ ?% i ] returns a Boolean indicating whether the index i exists.
[ # k$ ] returns the index for the key k$.
[ $$ k$ ] returns the correct key string (upper and lower) for key k$.

Example

Example 1

Dim a As Hash String, e As String

Hash Add a[], "a"

Hash Add a[], "b"

Hash Add a[], "c"

Hash Add a[], "d"

a[% a[%]] = "e"         // replace last element

a[% 1] = "1"            // replace first element

a[ "Key" ] = "f"        // add element

Print a[$$ "key"]       // prints Key

For Each e In a[]       // iterate over table

Print "(Pos)" & Each, " (element) " & e

Next

Example 2

Dim ha As Hash Int

// The value 27 will be assigned to element 1 with the key "a" and the index 1

ha["a"] = 27

// The value 29 will be assigned to element 2 with the key "xyz" and the index 2

ha["xyz"] = 29

// Output of element with index number 1:

Trace ha[% 1]           // Prints 27

// Output by using the key "a":

Trace ha["a"]           // Prints 27

// Output of element with index number 2:

Trace ha[% 2]           // Prints 29

// Output by using the key "xyz":

Trace ha["xyz"]         // Prints 29

// To get the key for the second element:

Trace ha[$ 2]           // Prints xyz

// The only way to add a value without using a key

Hash Add ha[], 100

// Call Proc dst to iterate through the Hash Table

dst(ha[])

// Check is key "a" exists:

Trace ha[? "a"]         // Prints True

// Check the correct formatting of key "a":

Trace ha[$$ "A"]        // Prints a

// Check to see if 3 is a valid index or not:

Trace ha[? % 3]         // Prints True

// To get the index which corresponds to key "xyz"

Trace ha[# "xyz"]       // Prints 2

// Request the number of elements in the Hash ha[]

Trace ha[%]             // Prints 3

Debug.Show

 

Procedure dst(ByRef h As Hash Int)

// Remember h is read-only

Local i%, j%

For Each i% In h[]

Debug.Print i%, Each, h[$ Each]

Next

EndProc

Remarks

A Hash is passed ByRef to subroutines. Unfortunately, the argument is a const variable, so that the Hash is read-only and can't be modified.

Known Issues

Although the initial documentation says that it is possible to create a Hash Table full of Objects, this does not seem to be the case as there seems to be no way to assign the objects to the table. If the code below is run, a Syntax Error is thrown.

Dim a As Hash Object

Dim b As Object

Hash Add a["key"], b

[Reported by James Gaite, 15/02/2017]


In addition, although syntactically it is possible to add a Hash Table as a property of a User-defined Type, there is no means of accessing it and, as UDTs in GFABasic are static, there is no room for the Hash to expand to accept new values.
[Reported by Garibaldi, 16/11/2016]

See Also

Hash Add, Hash Erase, Hash Input, Hash Load, Hash Remove, Hash Save, Hash Sort, Hash Write

{Created by Sjouke Hamstra; Last updated: 29/05/2023 by James Gaite}