Antares
Spell Reviewer
- Joined
- Dec 13, 2009
- Messages
- 982
Introduction
Hashtables are notoriously difficult to understand for those who have never worked with them, since they are an abstract concept that has a very unintuitive implementation in GUI. While there are already tutorials on using hashtables in GUI, I have the sense that the most difficult part about hashtables is not learning to work with them, but just understanding the basic concept; to have that first aha moment. Therefore, this tutorial will have a more long-winded approach in explaining the concept and only touch on the GUI-specifics briefly. For that, I will refer you to other tutorials at the end.
We will start our journey at Excel sheets (or OpenOffice tables, Google Docs tables etc.), then move on to Lua tables, since they're simpler than hashtables and much easier to understand, before we then finally arrive at GUI hashtables.
Excel Sheets
Meet Alice and Bob. They're a couple living in a small fishing town in northern Lordaeron.
For our RPG, we want to create a table containing background information about all the NPCs in our world. In an offline pen-and-paper RPG, we might achieve this with an Excel sheet that all players can pull up on their phone at any time. The columns represent our characters and the rows represent different attributes that we want to store.
Now, if we want to find out what Alice's occupation is, we just need to go to the Alice column and the occupation row and we will find the information there. Note that the order of our columns and our rows and even what we chose to be our columns vs. what we chose to be our rows is arbitrary. This table contains the same information as the one above:
This will be important later on.
Lua Tables
Tables in Lua are often praised as being one of its best features for how powerful and how easy to use they are. They are what is called a dictionary or associative array. In a regular array, like the ones we have in GUI, we can only use integers as the "keys" for our array. A key is a position at which data is stored. For example:
In Lua, we can use anything as keys for our array, including Alice and Bob. So, we can do something like this, where we use the unit variables udg_Alice and udg_Bob directly as the keys of our array:
However, this table contains only the occupation, not age and spouse. To create a data table that contains all of the information, we need to create a two-dimensional table, much like our Excel sheet.
Here, we have not one, but two keys. We use strings as the parent key (representing the rows of the Excel sheet), and the unit variables Alice and Bob as the child keys (representing the columns).
Because mapmakers do not have the option to use units directly as keys in arrays in GUI, the most common workaround has always been to use Unit Indexers. These systems use the Custom Value of units to assign a unique integer to each unit on the map. This integer is used as the key in the arrays to find where the data is stored for that unit. Going back to our Excel sheet example, in Lua, if we want to find Alice's occupation, we just tell our computer to find the column "Alice", while in GUI, we have to tell our computer specifically that information for Alice is stored at column C.
Hashtables
Unlike Lua tables, hashtables only take integers as keys, but we can still use hashtables to achieve exactly what we achieved with the Lua tables with one extra step.
First, we create our hashtable:
This might as well be Chinese. Save Value as Value of Value?!?!?!? What the hell is that supposed to mean? No idea how that wording made it into the editor. It will be much clearer once we rephrase this as such:
Because a hashtable only uses integer keys, we have to use an extra step that we didn't have to with Lua tables. To this end, we can use two functions:
Hashtable - Get Handle Id
This function converts any handle (unit, destructable, special effect, timer etc.) into a unique integer. It is the most important function when working with hashtables. It has, however, a few annoying quirks in GUI.
Hashtable - Get String Id
Much like GetHandleId, but converts a string into a unique integer.
With these functions, we can finally store the data in our hashtable for Alice:
If we want to read the data from the table, we use the Hashtable - LoadString function:
Why are hashtables useful?
Everything we've done so far could just as easily be achieved by using regular arrays and a Unit Indexer. But with hashtables, we can not only attach data to units, but to any handle. Specifically, we can store data attached to a timer. This is incredibly useful when coding in JASS to make spells MUI. We can store a unit to the key of a timer, then, when the timer expires, we can retrieve that unit and perform our actions on it. However, to get the same benefit in GUI requires a few more hoops to jump through.
We can also store data attached to unit type keys, ability type keys etc. And finally, we can store values to string keys. Take this trigger for example:
So far, we've only stored constants in a hashtable, but, of course, a hashtable can also be used to store dynamic data, for example the life left on a damage-absorbing shield buff that is active on a unit. To do this, we first load the current value from the hashtable, do our arithmetic, then write the modified value back into the same location in the hashtable.
Closing Thoughts
I hope I was successful in helping you wrap your head around hashtables. As you get more comfortable using hashtables, you will identify more and more problems that can be solved by using them - until you use them for everything!

For a more in-depth tutorial on how to work with hashtables in GUI, I refer you to A Complete Beginners Guide to Hashtables by Jazztastic and Hashtable and MUI by wyrmlord. As an exercise, you can try to create Alice and Bob in a map and write a function that prints out their background information when the player selects one of them.
Hashtables are notoriously difficult to understand for those who have never worked with them, since they are an abstract concept that has a very unintuitive implementation in GUI. While there are already tutorials on using hashtables in GUI, I have the sense that the most difficult part about hashtables is not learning to work with them, but just understanding the basic concept; to have that first aha moment. Therefore, this tutorial will have a more long-winded approach in explaining the concept and only touch on the GUI-specifics briefly. For that, I will refer you to other tutorials at the end.
We will start our journey at Excel sheets (or OpenOffice tables, Google Docs tables etc.), then move on to Lua tables, since they're simpler than hashtables and much easier to understand, before we then finally arrive at GUI hashtables.
Excel Sheets
Meet Alice and Bob. They're a couple living in a small fishing town in northern Lordaeron.
For our RPG, we want to create a table containing background information about all the NPCs in our world. In an offline pen-and-paper RPG, we might achieve this with an Excel sheet that all players can pull up on their phone at any time. The columns represent our characters and the rows represent different attributes that we want to store.
Now, if we want to find out what Alice's occupation is, we just need to go to the Alice column and the occupation row and we will find the information there. Note that the order of our columns and our rows and even what we chose to be our columns vs. what we chose to be our rows is arbitrary. This table contains the same information as the one above:
This will be important later on.
Lua Tables
Tables in Lua are often praised as being one of its best features for how powerful and how easy to use they are. They are what is called a dictionary or associative array. In a regular array, like the ones we have in GUI, we can only use integers as the "keys" for our array. A key is a position at which data is stored. For example:
-
Set VariableSet NPCs[1] = Alice
-
Set VariableSet NPCs[2] = Bob
In Lua, we can use anything as keys for our array, including Alice and Bob. So, we can do something like this, where we use the unit variables udg_Alice and udg_Bob directly as the keys of our array:
Lua:
Occupation[udg_Alice] = "Tailor"
Occupation[udg_Bob] = "Fisherman"
Lua:
BackGroundInformation["Age"][udg_Alice] = 26
BackGroundInformation["Age"][udg_Bob] = 32
BackGroundInformation["Spouse"][udg_Alice] = udg_Bob
BackGroundInformation["Spouse"][udg_Bob] = udg_Alice
BackGroundInformation["Occupation"][udg_Alice] = "Tailor"
BackGroundInformation["Occupation"][udg_Bob] = "Fisherman"
Because mapmakers do not have the option to use units directly as keys in arrays in GUI, the most common workaround has always been to use Unit Indexers. These systems use the Custom Value of units to assign a unique integer to each unit on the map. This integer is used as the key in the arrays to find where the data is stored for that unit. Going back to our Excel sheet example, in Lua, if we want to find Alice's occupation, we just tell our computer to find the column "Alice", while in GUI, we have to tell our computer specifically that information for Alice is stored at column C.
Hashtables
Unlike Lua tables, hashtables only take integers as keys, but we can still use hashtables to achieve exactly what we achieved with the Lua tables with one extra step.
First, we create our hashtable:
-
Hashtable - Create a hashtable
-
Set VariableSet BackgroundInformation = (Last created hashtable)
This might as well be Chinese. Save Value as Value of Value?!?!?!? What the hell is that supposed to mean? No idea how that wording made it into the editor. It will be much clearer once we rephrase this as such:
-
Hashtable - Save Tailor as (Child Key) of (Parent Key) in BackgroundInformation.
-
Hashtable - Save Tailor at (Row), (Column) in BackgroundInformation.
Because a hashtable only uses integer keys, we have to use an extra step that we didn't have to with Lua tables. To this end, we can use two functions:
Hashtable - Get Handle Id
This function converts any handle (unit, destructable, special effect, timer etc.) into a unique integer. It is the most important function when working with hashtables. It has, however, a few annoying quirks in GUI.
Hashtable - Get String Id
Much like GetHandleId, but converts a string into a unique integer.
With these functions, we can finally store the data in our hashtable for Alice:
-
Unit - Create 1 Villager (Female) for Neutral Passive at MyLocation facing Default building facing degrees
-
Set VariableSet Alice = (Last created unit)
-
Custom script: set udg_ChildKey = GetHandleId(udg_Alice)
-
Hashtable - Save Tailor as udg_ChildKey of (Key Occupation.) in BackgroundInformation.
-
Hashtable - Save 26 as udg_ChildKey of (Key Age.) in BackgroundInformation.
-
Hashtable - Save Handle Of Bob as udg_ChildKey of (Key Spouse.) in BackgroundInformation.
That we need to use a Custom Script line to convert the Alice unit variable to an integer is one of the annoying quirks of GUI hashtables. But we can use event responses such as Triggering Unit and Last Created Unit without the need for custom script. | |
You might ask why we don't just use Get Handle Id and Get String Id to convert our handles into integers and use those as the keys in a plain-old regular array. That's because the keys of regular JASS arrays are limited to the range 0 to 32768, while the keys of hashtables can take any value. These two data structures are optimized for different purposes. |
If we want to read the data from the table, we use the Hashtable - LoadString function:
-
Custom script: udg_ChildKey = GetHandleId(udg_Alice)
-
Set VariableSet Occupation = (Load udg_ChildKey of (Key Occupation.) from BackgroundInformation.)
Why are hashtables useful?
Everything we've done so far could just as easily be achieved by using regular arrays and a Unit Indexer. But with hashtables, we can not only attach data to units, but to any handle. Specifically, we can store data attached to a timer. This is incredibly useful when coding in JASS to make spells MUI. We can store a unit to the key of a timer, then, when the timer expires, we can retrieve that unit and perform our actions on it. However, to get the same benefit in GUI requires a few more hoops to jump through.
We can also store data attached to unit type keys, ability type keys etc. And finally, we can store values to string keys. Take this trigger for example:
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Entered chat string) Equal to -pizza
-
-
Then - Actions
-
Trigger - Run CreatePizza <gen> (ignoring conditions)
-
-
Else - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Entered chat string) Equal to -spaghetti
-
-
Then - Actions
-
Trigger - Run CreateSpaghetti <gen> (ignoring conditions)
-
-
Else - Actions
-
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
-
If - Conditions
-
(Entered chat string) Equal to -burger
-
-
Then - Actions
-
Trigger - Run CreateBurger <gen> (ignoring conditions)
-
-
Else - Actions
-
-
-
-
-
-
Hashtable - Save Handle OfCreatePizza <gen> as 0 of (Key -pizza.) in FoodTriggers.
-
Hashtable - Save Handle OfCreateSpaghetti <gen> as 0 of (Key -spaghetti.) in FoodTriggers.
-
Hashtable - Save Handle OfCreateBurger <gen> as 0 of (Key -burger.) in FoodTriggers.
-
Trigger - Run (Load 0 of (Key (Entered chat string).) in FoodTriggers.) (ignoring conditions)
So far, we've only stored constants in a hashtable, but, of course, a hashtable can also be used to store dynamic data, for example the life left on a damage-absorbing shield buff that is active on a unit. To do this, we first load the current value from the hashtable, do our arithmetic, then write the modified value back into the same location in the hashtable.
Closing Thoughts
I hope I was successful in helping you wrap your head around hashtables. As you get more comfortable using hashtables, you will identify more and more problems that can be solved by using them - until you use them for everything!


For a more in-depth tutorial on how to work with hashtables in GUI, I refer you to A Complete Beginners Guide to Hashtables by Jazztastic and Hashtable and MUI by wyrmlord. As an exercise, you can try to create Alice and Bob in a map and write a function that prints out their background information when the player selects one of them.
P.S. Don't worry, Alice and Bob managed to flee by sea when the Scourge came. |
Last edited: