Tinderbox v9 Icon

Dictionary-Type Attributes

Dictionary

A Dictionary attribute replaces like the older Tinderbox feature of lookup tables, as a list of paired keys with values: key:value; 

The key part comes first with a terminating colon. The value part follows, terminated by a semi-colon. White space handling in key:value pairs is described below.

Dictionaries are faster to construct, and large dictionaries are far faster to check, than lookup tables. Dictionaries are not generally intended for handing large/complex values or for values including punctuation and symbols. A Dictionary may be considered better for tasks previously configured using look-up lists.

Like other attribute types, a Dictionary follows normal rules of scope and inheritance. A note using a prototype with a Dictionary holding data, will inherit that data dictionary. Similar to a Set type, a Dictionary does not allow duplicate keys, but multiple keys may use the same value. A note using a prototype with a dictionary holding data, will inherit that dictionary.

A key may have multiple values; this can be either []-enclosed List-type or {}-enclosed Dictionary-type data. For example, the dictionary:

{Tinderbox: 1;Storyspace: {Editor: 2; Reader:3}} 

contains two elements. The first has a key of "Tinderbox" and a value of 1. The second has a key of "Storyspace" and the value that is itself a dictionary, {Editor: 2; Reader:3}.

Dictionary key:value syntax

A dictionary collects pairs of strings separated by a colon. The first string is the key, and the second string is the value. The dictionary() operator creates a dictionary (in the current note), here with 3 such key:value pairs. The first form is best practice:.

$MyDictionary={cat:animal; dog:animal; rock: mineral}; 

$MyDictionary=dictionary("cat:animal; dog:animal; rock: mineral"); 

The key "cat" has the value "animal", while the key "rock" has the value "mineral".

Although it is still possible, via legacy support, to populate a directory by passing a dictionary-formatted list as a quoted string to a Dictionary-type attribute, this is deprecated in favour of the {} method, or using the dictionary() operator is explicit and indicates intent unambiguously when parsed by Tinderbox. See dictionary() for usage.

Case-sensitivity

A key is case-sensitive and must be unique to the dictionary; the value may be the same as values for different keys within the current dictionary. Rather like the Set data type, duplicates are weeded. If a new key:pair is added to a dictionary and the key (case-sensitively) already exists, the existing value (only) for that key is updated to use the value from the new pair.

$MyDictionary = dictionary("cat:animal; dog:animal; rock: mineral"); 

$MyDictionary = $MyDictionary + "cat:mammal"; 

Now, the value of key "cat" becomes "mammal" and the older value is lost.

Use of whitespace, symbols, quotes, etc., with keys & values

Any whitespace either side of a colon (:), or semi-colon (;), or at beginning or end of dictionary data is ignored. As the colon (:) and semi-colon (;) characters are used as delimiters in the stored Dictionary data, they should also not be used within key names or values.

The expectation is that keys and values will be simple strings or numbers, so avoid use of characters like punctuation as you may experience unexpected results; additionally avoid using parentheses (), square [] or curly {} brackets, backward \ and forward / slashes, single/double quotes or commas.

A good rule of thumb is to think hard if using other than A-za-z0-9 or underscore/hyphen/period (the period might be needed for a decimal number value).

Adding key:value pairs

To add to a new key:value pair, use addition, as with Lists and Sets…

$MyDictionary = $MyDictionary + {apple:plant}; 

$MyDictionary += {apple:plant}"; 

adds they key "apple" and associates it with the value "plant". If the key was already found in the dictionary, its value is replaced by the new value. If the key was not found in the dictionary, both the new key and the new value are added.

As well as using a literal value, the key (and value) to be added can be give as an attribute value or variable:

$MyString = "apple:plant"; $MyDictionary += $MyString; 

var:string vKey = "apple:plant"; $MyDictionary += vKey; 

Deleting keys (implicitly key:value pairs)

Entries can be deleted from a dictionary by subtracting the key:

$MyDictionary = dictionary("dog:animal; cat:animal; rock:mineral"); 

$MyDictionary = $MyDictionary - "dog"; // gives "cat:animal; rock:mineral" 

or in newer form:

$MyDictionary -= "dog"; // gives "cat:animal; rock:mineral" 

Be aware that setting an empty value for a key doesn't delete the key:

$MyDictionary[somekey] = ""; 

leaves the key 'somekey' with no value, which is not encouraged (q.v. below).

As well as using a literal value, the key to be removed can be give as an attribute value or variable:

$MyString = "dog"; $MyDictionary -= $MyString; 

var:string vKey = "dog"; $MyDictionary -= vKey; 

It is not possible to subtract a list of keys. Instead, such a list must be iterated as a succession of individual key deletions. Alternatively simple set the key's value to a new literal string/list/dictionary, thus completely replacing the existing value(s).

Changing the value of a key

New values may be assigned to specific dictionary keys.

$MyDictionary[apple] = "pie" 

Adds the key "apple" to $MyDictionary with the value "pie". If the dictionary previously contained a value for "apple", it is replaced by "pie"; if not, a new key and a new value are added to the dictionary. From v9.1.0, .add() can be used:

$MyDictionary.add("apple","pie"); 

Note that the += and -= operators are not currently available for changes to dictionary (numerical) values of the form

$MyDictionary[key] += 1; WRONG!

Instead, use the conventional form:

$MyDictionary[key] = $MyDictionary["key"] + 1; 

Deleting the (single) value of a key

Ideally in such a case remove the key. However is possible to delete a key's value, by setting it to an empty string "" (or reading from a stored value that is such). To set the value of key 'apple' to "":

$MyDictionary[apple] = "" 

Generally, the expectation is that a key has an actual value.

Keys with multi-item values are supported using [] or {} notation

From v9.6.0, Dictionary key values can be multi-valued using either the new [] (list/set) or {} (dictionary) notation. This holds for creating dictionaries or setting key values. When retrieving a multi-value result pass the data to an appropriately type attribute or variable. The data can then be accessed using appropriate key or list address syntax. Examples of nested multi-value values:

$MyDictionary={cat:animal; dog:animal; rocks:{granite:mineral;basalt:mineral}}; 

$MyDictionary={cat:animal; dogs{terrier:dog;labrador:dog}; rock: mineral}; 

Legacy behaviour: Prior to v9.6.0, a value could not contain more than one value The value for a key 'pie' might reasonably be apple, lemon and quince. Whilst it was possible to define a dictionary like this:

$MyDictionary["pie"] = "apple;lemon;quince" 

… the fact a semi-colon is used as both a list delimiter (within the value) and as a key:value pair delimiter, means Tinderbox currently does not know how to parse this; work is in hand to support multi-item value, i.e. lists.

Temporary note. At present (v9.6.1) generating a dictionary with nested multi-values (list/dictionary) is possible only if using literal string values but not if using variables/attribute values. This is likely a by-product of the new [ ] and { } notations and subject to change/fix.

Merging Dictionaries

Dictionaries may be merged by adding them.

$MyDictionary = $MyDictionary+"apple:plant" 

adds they key "apple" and associates it with the value "plant". If the key was already found in the dictionary, its value is replaced by the new value. If the key was not found in the dictionary, both the new key and the new value are added.

It is possible to add two dictionaries.

$MyNewDictionary = $MyDictionary+$MyOtherDictionary 

Note that if the dictionaries share (case-sensitive) keys that have differing values, the values from the last-added, therefore those in $MyDictionary, will replace those in $MyDictionary. Thus:

$MyFirstDictionary = dictionary("apple:fruit; granite:mineral"); 

$MyOtherDictionary = dictionary("pear:fruit; granite:rock"); 

$MyDictionary = $MyFirstDictionary + $MyOtherDictionary; 

MyDictionary now contains "granite: rock; pear: fruit; apple: fruit" 

Note the order of dictionary items is re-ordered, reinforcing the point that additions/subtraction of dictionary data may alter item order, and which the user does not control. It is not possible to:

Dictionaries lack the 'default' key used by look-up lists

User of look-up lists with list-type data might assume the same notion holds for Dictionary-type: it does not! It is still possible to define a 'default' key but using it requires a little extra code. Whilst it is possible to check if a key exists with Dictionary.contains(), it may be more useful to check for a default empty ("") value being returned. For instance, instead of, in a .each(aKey){} loop, where you might code:

$MyString = $MyDictionary[aKey]; 

consider (and assuming a 'default' key/value exists):

if($MyDictionary[aKey]){$MyString = $MyDictionary[aKey];}else{}$MyString = $MyDictionary[default];}; 

or:

if($MyDictionary.contains(aKey)){$MyString = $MyDictionary[aKey];}else{}$MyString = $MyDictionary[default];}; 

But, the key point is that is a default response is needed, the user must (a) define the 'default' key:vale pair and (b) add the code to invoke it. More code-savvy users may choose to encapsulate this in a user function.

Dictionary and values()

You can get the values of a Dictionary, but you cannot look up a key that corresponds to a given value. Remember, multiple keys may same value. Therefore, using values() with dictionaries is not recommended as this returns all the unique key:pair values as opposed to only keys or only values.

Iterating Dictionaries

Use Dictionary.keys to get a list of the keys and then iterate that list using List.each().

Default/Empty value

If a requested key is not defined, or the key has no value, an empty string is returned.

Dictionary sorting

Not applicable, as Dictionaries cannot be sorted. As a Dictionary is addressed via a key value rather than a list offset, the stored order for keys is moot. By observation, a Dictionary is generally stored in key lexical sort order but this should not be assumed to always be the case.

Whilst a Dictionary itself cannot be sorted, it is possible to make a list of the keys then sort and iterate that list. for example:

	var:list vKeyList = $MyDictionary.keys;
	vKeyList = vKeyList.sort; // Use .nsort if keys are numbers
	var:list vSortResults; // Use List so it stays sorted
	vKeyList.each(aKey){
		vSortResults+=(aKey+" | "+$MyDictionary[aKey]);
	};
	//Test
	//$Text = vSortResults.format("\n"); 

Note that the initial sort could be lexical (.sort), lexical case insensitive (.isort) or numerical (.nsort)

Additional Dictionary definition mark-up

From v9.5.0, Dictionaries gain additional new mark-up. Dictionaries may be written by enclosing them in braces, for example a dictionary with two key:value pair elements:

$MyDictionary = dictionary({Dog: animal; Crocus: plant}); 

The use of the braces removes the need to use quotes around string values.

This new form of Dictionary-type data allows for nesting; for example, the dictionary

{Tinderbox: 1;Storyspace: {Editor: 2; Reader:3}} 

contains two elements. The first has a key of "Tinderbox" and a value of 1. The second has a key of "Storyspace" and the value that is itself a dictionary, {Editor: 2; Reader:3} .

The dictionary .add() and .extend() operators now take a single argument — a dictionary of elements which will replace or extend the current elements.

Dictionary-type System Attributes

Built-in attributes of the date data type are listed below: