The HASH function creates a new hash. A hash is a compound data type that contains key-value pairs of different data types, including any mixture of scalars, arrays, structures, pointers, object references, lists, and other hashes.

Hashes have the following properties:

  • Elements in a hash are unordered, and are indexed by a scalar key. You can use ORDEREDHASH if you need to preserve order.
  • The key can be a scalar string or number. String keys are case sensitive unless the FOLD_CASE keyword is set. You can use DICTIONARY for case-insensitive keys that can also be accessed using "dot" notation.
  • Hashes can change their size, growing and shrinking as elements are added or deleted.
  • Individual hash elements can change their value and data type without a performance penalty.

Note: While you can use IDL's array syntax to access elements in a hash, it is important to remember that a hash does not behave like an array in all cases. See below for a full description of the characteristics of a hash.

Methods and Additional Information

The HASH function and class was ported from PRO code to C/C++ code in 8.8.1. You can run the SAVEFILE_CLEANUP procedure to inspect an older save file and remove any routines that might cause problems in IDL 8.8.1 and newer. See SAVEFILE_CLEANUP for more information.

Examples


Create a hash containing three key-value pairs, with strings for keys

hash = HASH("one", 1.0, "blue", [255,0,0], "Pi", !DPI)
PRINT, N_ELEMENTS(hash)

IDL Prints:

3

Create a hash with a mixture of number and string keys

hash = HASH(80301, 'Boulder', 'Joe', 48236)
PRINT, hash[80301]
PRINT, hash['Joe']

IDL Prints:

Boulder
48236

Create a hash containing all of the elements of a list

keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
values = LIST('one', 2.0, 3, 4l, PTR_NEW(5), {n:6}, COMPLEX(7,0))
hash = HASH(keys, values)
PRINT, N_ELEMENTS(hash)

IDL Prints:

7

Create a hash from a structure, and also convert any substructures into hashes

struct = {FIELD1: 4.0, FIELD2: {SUBFIELD1: "hello", SUBFIELD2: 3.14}}
hash = HASH(struct, /EXTRACT)
PRINT, hash
PRINT, hash['FIELD2']

IDL Prints:

FIELD2: HASH  <ID=25  NELEMENTS=2>
FIELD1:       4.00000
 
SUBFIELD1: hello
SUBFIELD2:       3.14000

Syntax


Result = HASH( Key1, Value1, Key2, Value2, ... Keyn, Valuen, /EXTRACT, /FOLD_CASE, /NO_COPY )

or

Result = HASH( Keys, Values, /EXTRACT, /FOLD_CASE )

or

Result = HASH( Keys , /FOLD_CASE )

or

Result = HASH( Structure, /EXTRACT, /FOLD_CASE, /LOWERCASE)

Return Value


Returns a reference to a newly-created hash.

Arguments


Keyn

Each Key argument can be a scalar string or number. The corresponding Value can be a scalar or array of any IDL data type including !NULL.

Each Key argument can also be an array or list, in which case the corresponding Value must be a scalar, an array or a list. If Value is a scalar, then that value is copied into every key. Otherwise, if Value is an array or a list, it must contain the same number of elements as the keys. In this case each element of the Key and Value is inserted as a separate key-value pair. If a given key occurs more than once within the input arguments, the last value will be retained.

If only Keys is supplied (as either a scalar, an array, or a list), then the corresponding values will be set to the default value of !NULL.

If no keys or values are supplied, an empty hash is returned.

Note: For strings, the key is case sensitive unless the FOLD_CASE keyword is set. For example, "Abc" and "abc" will be considered as two separate keys. For numbers, the actual data type does not matter, only the numeric value is used. For example, 1b (byte), 1 (int), and 1.0 (float) will all equate to the same key. Note however that because of the precision of floating-point arithmetic, single-precision and double-precision keys may be considered as different numbers. For example, 0.1 (float) and 0.1d (double) will not equate to the same key.

Valuen

Each Value argument can be a variable or expression of any IDL data type including !NULL.

Structure

Instead of passing in keys or values, a single IDL structure may be passed in. In this case, each tag/value pair within the structure will be inserted within the hash.

Note: Even though the structure itself is decomposed into key/value pairs, any substructures within the structure will be passed in as a single "value" for that particular key, unless you set the EXTRACT keyword.

Keywords


EXTRACT

By default, all values are put into the hash unchanged. If the EXTRACT keyword is set, then for any value which is a structure, that structure will be decomposed into key/value pairs (and also recursively for any substructures).

FOLD_CASE

By default, string keys are case sensitive. For example, "Abc" and "abc" will be considered as two separate keys. If the FOLD_CASE keyword is set, then the case for string keys will be ignored when accessing keys, adding new keys, removing keys, or changing values. For example:

h = HASH('My key', 1, /FOLD_CASE)
h['MY KEY'] = 2
print, h['my key']
print, h.Keys()

IDL prints:

2
My key

Note: As shown in the example, even though the key matching is case insensitive, HASH always preserves the case of the key when it was originally set.

Note: If FOLD_CASE is set, then any other hashes returned by this HASH (for example with array indexing or the "+" operator) will also have the FOLD_CASE flag set.

Note: The FOLD_CASE keyword has no effect for numeric keys.

NO_COPY

If the NO_COPY keyword is set, the value data is taken away from the Value variable and attached directly to the hash variable. The default behavior is to make a copy of the input values.

LOWERCASE

By default, when extracting key/value pairs from a structure, the keys are all uppercase. Set this keyword to use lowercase for all of the keys. This keyword is ignored if the input is not a structure.

Hash::Count


The Hash::Count function method returns the number of elements in the hash. Optionally, the Hash::Count method can return the number of matches to a given value.

Syntax


Result = hash.Count( [Value] )

Return Value


By default, returns an integer containing the number of elements in the hash. If Value is supplied, then returns an integer giving the number of occurrences of Value within the hash.

Note: See the Hash::Where method for the rules that are used for comparing values.

Arguments


Value

A value to search for within the hash.

Keywords


None

Hash::Filter


The Hash::Filter method passes each hash value through a boolean filter function or Lambda function and returns only values that pass the test.

Examples


Create a new file called myfilterfunction.pro that keeps only prime numbers:

function myfilterfunction, value
  return, value le 3 || MIN(value mod [2:FIX(SQRT(value))])
end

Use your function to return only the prime numbers in hash:

var = HASH('A', 4, 'B', 5, 'C', 499, 'D', 1000)
newvar = var.Filter('myfilterfunction')

IDL prints:

IDL> newvar
{
  "B": 5,
  "C": 499
}

Now use a Lambda function to avoid creating a separate routine:

var = HASH('A', 4, 'B', 5, 'C', 499, 'D', 1000)
newvar = var.Filter(Lambda(n:n le 3 || MIN(n mod [2:FIX(SQRT(n))])))

Tip: The COMPILE_CODE procedure can be used to generate functions on the fly.

Syntax


Result = hash.Filter( Function, Args )

Return Value


The result is a hash containing only the key-value pairs where the filter function returned a non-zero number for that input value. If none of the values are good then the method returns an empty hash.

Arguments


Function

A string or Lambda expression giving the name of the user-defined function to call for each value. For user-defined functions, your function should have the form:

function myfunction, value
  result = ...
  return, result
end

The result should be a scalar value containing a non-zero value if the input value "passes" your filter test, and a zero value if the input value "fails" your filter test.

Args

You can specify any number of additional arguments to be passed on to your filter or Lambda function. Each argument must be either a scalar or a hash. For scalar arguments, ::Filter will pass in that same scalar value to each call of the filter function. For hash arguments, ::Filter will pull out the value corresponding to the current key and pass that into your filter function as a scalar.

Note: If your argument is a hash, it must contain the same keys as the input hash.

Keywords


None.

Hash::HasKey


The Hash::HasKey function method tests whether a key or set of keys exists in a hash.

Examples


hash = HASH('black', 0, 'gray', 128, 'grey', 128, 'white', 255)
print, hash.HasKey('gray')
print, hash.HasKey(['grey','red','white'])

IDL Prints:

1
1 0 1

Syntax


Result = hash.HasKey(Keys )

Return Value


If Keys is a scalar, then returns a scalar 1 if the key exists in the hash, or a 0 otherwise. If Keys is an array or list, then returns an array of 0's or 1's.

Arguments


Keys

A scalar key, or an array or list of keys.

Keywords


None.

Hash::IsEmpty


The Hash::IsEmpty function method tests whether the hash is empty or not.

Syntax


Result = hash.IsEmpty( )

Return Value


Returns 1 if the hash contains zero elements, and 0 otherwise.

Arguments


None.

Keywords


None.

Hash::IsFoldCase


The Hash::IsFoldCase function method tests whether the hash is using case-insensitive keys or not (i.e. was the hash created with FOLD_CASE).

Syntax


Result = hash.IsFoldCase( )

Return Value


Returns a boolean True (1) if the hash is using case-insensitive keys, and False (0) otherwise.

Arguments


None.

Keywords


None.

Hash::Keys


The Hash::Keys function method returns a LIST containing all keys in a hash. The order of key/value pairs within hash.Keys() and hash.Values() is guaranteed to remain the same as long as no items are added or removed from the hash.

Note: If this is an Ordered Hash then the order of the key/value pairs will always be the same.

Examples


hash = HASH('black', 0, 'gray', 128, 'grey', 128, 'white', 255)
list = hash.Keys()
print, list

IDL Prints:

white
black
gray
grey

Syntax


Result = hash.Keys( )

Return Value


Returns a list containing all of the keys. If the hash is empty then an empty list is returned.

Arguments


None.

Keywords


None.

Hash::Map


The Hash::Map method passes each hash value through a user-defined function or Lambda function.

Examples


Create a new file called mymapfunction.pro that adds a file suffix to a file name:

function mymapfunction, x, suffix
  return, x + "." + suffix
end

Use your function to map a hash to the new values:

var = HASH('File1', 'a', 'File2', 'b')
; Each var value is passed in separately
newvar = var.Map('mymapfunction', 'pro')

IDL prints:

IDL> var
{
  "File1": "a",
  "File2": "b"
}
IDL> newvar
{
  "File1": "a.pro",
  "File2": "b.pro"
}

Now use a Lambda function to avoid creating a separate routine:

var = HASH('File1', 'a', 'File2', 'b')
; Each var value is passed in separately
newvar = var.Map(Lambda(x,suffix:x + "." + suffix), 'pro')

Tip: The COMPILE_CODE procedure can be used to generate functions on the fly.

Syntax


Result = hash.Map( Function, Args )

Return Value


The result is a hash containing the new key-value pairs.

Arguments


Function

A string or Lambda expression giving the name of the user-defined function to call for each value. For user-defined functions, your function should have the form:

function myfunction, value
  result = ...
  return, result
end

The result should be a scalar value.

Args

You can specify any number of additional arguments to be passed on to your user-defined function or Lambda function. Each argument must be either a scalar or a hash. For scalar arguments, ::Map will pass in that same scalar value to each call of the function. For hash arguments, ::Map will pull out the value corresponding to the current key and pass that into your function as a scalar.

Note: If your argument is a hash, it must contain the same keys as the input hash.

Keywords


None.

Hash::Reduce


The Hash::Reduce method passes each data value cumulatively through a user-defined function or Lambda function and returns a single scalar result.

Note: The Reduce method passes in the values in the order that they are stored within the hash, not in the order in which the values were originally added to the hash. To preserve the order, use an OrderedHash instead.

Examples


Create a new file called myreducefunction.pro that adds up arrays (or concatenates strings):

function myreducefunction, accumvalue, value
  return, accumvalue + value
end

Use your function on a hash of key-value pairs:

var = HASH('key1', 1, 'key2', 2, 'key3', 3, 'key4', 4)
newvar = var.Reduce('myreducefunction')
PRINT, newvar

IDL prints:

10

Now use a Lambda function to avoid creating a separate routine:

var = HASH('key1', 1, 'key2', 2, 'key3', 3, 'key4', 4)
newvar = var.Reduce(Lambda(x,y:x+y))

Now try the same reduce function but with string keys. Notice that the order in which the strings are stored within the hash is not the same as the order that the values were originally added:

var = HASH('key1', 'a', 'key2', 'b', 'key3', 'c', 'key4', 'd')
newvar = var.Reduce(Lambda(x,y:x+y))

IDL prints:

badc

Tip: The COMPILE_CODE procedure can be used to generate functions on the fly.

Syntax


Result = hash.Reduce( Function, Args, VALUE=value)

Return Value


The result is a scalar value containing the cumulative result. The data type of the result will depend upon your calling function's result type.

If your input contains a single element then this value will be returned as the result without calling the function, unless the VALUE keyword is set, in which case the function will be called once.

Arguments


Function

A string or Lambda expression giving the name of the user-defined function to call for each value. For user-defined functions, your function should have the form:

function myfunction, accumvalue, value
  result = ...
  return, result
end

The result should be a scalar value that combines the current accumulated value (the first argument) and the current input value (the second argument).

Args

You can specify any number of additional arguments to be passed on to your user-define function or Lambda function. Each argument must be either a scalar or a hash. For scalar arguments, ::Reduce will pass in that same scalar value to each call of the filter function. For hash arguments, ::Reduce will pull out the value corresponding to the current key and pass that into your function as a scalar.

Note: If your argument is a hash, it must contain the same keys as the input hash.

Keywords


VALUE

Set this keyword to the starting value. If this keyword is set then this value will be passed into your function along with the first element of your input. If this keyword is not set then the first two elements will be passed into your function.

Hash::Remove


The Hash::Remove method removes elements from a hash and optionally returns the removed value.

Examples


Create a hash and print its contents:

hash = HASH("one", 1.0, "blue", [255,0,0], "Pi", !DPI)
PRINT, hash

IDL Prints:

Pi, 3.141592798.6
blue, 255       0       0
one, 1.00000

Now delete some hash elements and print the contents again:

hash.Remove, ["one", "Pi"]
PRINT, hash
PRINT, N_ELEMENTS(hash)

IDL Prints:

blue, 255       0       0
1

Now remove the last element off the hash, printing the removed value:

PRINT, hash.Remove()

IDL Prints:

255       0       0

Syntax


hash.Remove [, Keys] [, /ALL]

or

Result = hash.Remove( [, Keys] [, /ALL] )

Return Value


If Keys is a scalar or 1-element array, then the result is the value itself. If Keys is an array or list of keys, then the result is a hash containing the removed key-value pairs.

Note: If the hash is empty, calling the Hash::Remove() function method will throw an error. The Hash::Remove procedure method will quietly return.

Arguments


Keys

A scalar key or an array or list of keys to be removed. If no Keys are supplied, an arbitrarily-chosen element is removed.

Keywords


ALL

Set this keyword to remove all entries in Hash, leaving the hash empty, but still in existence.

Hash::ToStruct


The Hash::ToStruct function method returns an IDL structure containing all of the hash elements converted into tag/value pairs. Keys which are not strings will not be included in the structure. For string keys, any special characters in the string will be converted to underscores to produce a valid IDL tag name. If a value is undefined (!NULL) it will also be skipped (unless the MISSING keyword is set).

Note: Since the hash stores its key/value pairs in an arbitrary order, the order of tags within the resulting structure will also be arbitrary, even if the same structure was used to create the hash.

Note: If this is an Ordered Hash then the order of tags will be the same as the input structure.

Examples


hash = HASH('black', 0, 'gray', 128, 'grey', 128, 'white', 255, 'light red', 200)
HELP, hash.ToStruct()
 

IDL Prints:

** Structure <332a8ca8>, 5 tags, length=10, data length=10, refs=1:
LIGHT_RED       INT            200
WHITE               INT            255
BLACK              INT              0
GRAY                 INT            128
GREY                 INT            128
 

An example using the RECURSIVE keyword:

struct = {FIELD1: 4.0, FIELD2: {SUBFIELD1: "hello", SUBFIELD2: 3.14}}
hash = HASH(struct, /EXTRACT)
PRINT, hash.ToStruct(/RECURSIVE)

IDL Prints:

{{ hello      3.14000}      4.00000}

Syntax


Result = hash.ToStruct( [, MISSING=value] [, /NO_COPY] [, /RECURSIVE] [, SKIPPED=variable] )

Return Value


The result is an IDL structure containing the key/value pairs. If the hash is empty or contains no valid keys then !NULL is returned.

Arguments


None.

Keywords


MISSING

Set this keyword to the value to be returned for missing (!NULL) values. The default behavior of the Hash::ToStruct method is to skip any keys whose value is !NULL.

NO_COPY

Set this keyword to move each element from the hash to the output structure. When finished, the hash will be empty.

RECURSIVE

If this keyword is set, then any HASH values within the structure are also converted into structures using the ToStruct() method. The MISSING, NO_COPY, and RECURSIVE keywords are passed on to the recursive ToStruct() calls.

SKIPPED

Set this keyword to a named variable in which to return a variable of type LIST containing all of the skipped keys. A key will be skipped (not included in the result structure) under the following circumstances:

  • The key is not a string;
  • The key is already present in the structure (this can happen because keys are case sensitive while structure tags are case insensitive);
  • The value associated with a key is !NULL (unless the MISSING keyword is set).

Hash::Values


The Hash::Values function method returns a LIST containing all values in a hash.The order of key/value pairs within hash.Keys() and hash.Values() is guaranteed to remain the same as long as no items are added or removed from the hash.

Note: If this is an Ordered Hash then the order of the key/value pairs will always be the same.

Examples


hash = HASH('black', 0, 'gray', 128, 'grey', 128, 'white', 255)
list = hash.Values()
PRINT, list

IDL Prints:

255
0
128
128

Syntax


Result = hash.Values( )

Return Value


Returns a list containing all of the values. If the hash is empty then an empty list is returned.

Arguments


None.

Keywords


None.

Hash::Where


The Hash::Where function method returns a LIST of all keys that contain a certain value.

Note: This method returns a result that is equivalent to using the EQ operator, but also provides additional keywords that are not available with the operator.

Examples


The following example generates a random integer and an array of ten random integers (both between 0 and 9). The sample uses Hash::Where to determine if there are any matches of the value in the hash (the hash keys are the array indices).

keys = 'key' + STRTRIM(SINDGEN(10),2)
rndmVal = FIX(10 * RANDOMU(seed, 1))
rndmArr = FIX(10 * RANDOMU(seed, 10))
h = HASH(keys, rndmArr)
matches = h.Where(rndmVal)
PRINT, 'Random value = ', rndmVal
PRINT, 'Random array = ', rndmArr
HELP, matches
PRINT, 'Matching keys: ', matches, FORMAT=('(A)')

Sample output:

Random value =        8
Random array =        2       7       8       8       0       4       8       3       7       1
Matching keys:
key3
key2
key6

Syntax


Result = hash.Where( Value [, COMPLEMENT=variable] [, COUNT=variable] [, NCOMPLEMENT=variable] )

Return Value


Returns a list containing all of the keys that contain the value. If there are no matches, an empty list is returned. The following rules are used when comparing values:

  • If Value is a scalar number or string, the corresponding hash element must be equal to the same value (although the types may differ).
  • If Value is an array, the corresponding hash element must be an array of the same length, with identical values (although the types may differ).
  • If Value is a pointer or object, the corresponding hash element must be the same pointer or object reference.
  • If Value is a structure, it is compared to the corresponding hash element on a tag-by-tag basis (including nested structures) using the same rules as above.
  • If Value is another hash, the two hashes are compared on a key-by-key basis (using the above rules), and the result is a list containing the hash keys which exist in both hashes and have the same value.

Arguments


Value

A variable or expression of any IDL data type, including !NULL.

Keywords


COMPLEMENT

Set this keyword to a named variable that will return a list of keys that do not contain the value.

Note: If Value is another hash, the COMPLEMENT is a list containing all of the keys in both hashes that either do not exist in the other hash, or have a different value. In this case the number of keys in the COMPLEMENT may be greater than the number of keys in either original hash.

COUNT

Set this keyword to a named variable that will return the number of matches.

NCOMPLEMENT

Set this keyword to a named variable that will return the number of keys within the COMPLEMENT list.

Additional Information on Hashes


Concatenating Hashes


To combine two hashes to make a new hash, use the + operator:

hash1 = HASH('key1', 1, 'key2', 2, 'keydup', 'abc')
hash2 = HASH('key3', 'three', 'key4', 4.0, 'keydup', 'xyz')
hash3 = hash1 + hash2
PRINT, hash3

IDL Prints:

keydup, xyz
key2, 2
key1, 1
key4, 4.00000
key3, three

Note: If the two hashes have duplicate keys, the values will be taken from the second operand.

The + operator may also be used to combine a hash and an IDL structure to make a new hash:

hash1 = HASH('key1', 1, 'key2', 2, 'keydup', 'abc')
struct = {tag1: 'mytagvalue', tag2: 2.0}
hash3 = hash1 + struct
PRINT, hash3

IDL Prints:

keydup: abc
key2:        2
key1:        1
TAG2:       2.00000
TAG1: mytagvalue

Comparing Hashes


EQ

The EQ operator does a comparison of two hashes, or a hash and a value. For the case of two hashes, EQ returns a list of keys that exist in both hashes and have the same value. For the case of a hash and a value, EQ returns a list of keys that contain that value. In either case, if there are no matches, an empty list is returned.

For example, to compare two hashes:

hash1 = HASH('key1', 1, 'key2', 2, 'key3', 3, 'anotherkey', 3.14)
hash2 = HASH('key1', 1, 'key2', 2, 'key3', 3.5)
result = hash1 EQ hash2
HELP, result
PRINT, result

IDL Prints:

RESULT          LIST  <ID=114775  NELEMENTS=2>
key2
key1

To compare a hash and a value:

hash = HASH('key1', 1.414, 'key2', 3.14, 'key3', 1.414)
result = hash EQ 1.414    ; (or 1.414 EQ hash)
HELP, result
PRINT, result

IDL Prints:

RESULT          LIST  <ID=114789  NELEMENTS=2>
key1
key3

To compare a hash and a value that is not in the hash:

hash = HASH('key1', 1.414, 'key2', 3.14, 'key3', 1.414)
result = hash EQ 2.718    ; (or 2.718 EQ hash)
HELP, result

IDL Prints:

RESULT          LIST  <ID=114817  NELEMENTS=0>
 

Note: See the Hash::Where method for the rules that are used for comparing values.

NE

The NE operator behaves in the opposite manner of EQ. For NE with two hashes, the result is a list containing all of the keys in both hashes that either do not exist in the other hash, or have a different value. For NE with a hash and a value, the result is a list containing all of the keys that do not contain that value. In either case, if every element is a match, then an empty list is returned.

For example, to compare two hashes:

hash1 = HASH('key1', 1, 'key2', 2, 'key3', 3, 'anotherkey', 3.14)
hash2 = HASH('key1', 1, 'key2', 2, 'key3', 3.5)
result = hash1 NE hash2
HELP, result
PRINT, result

IDL Prints:

RESULT          LIST  <ID=114843  NELEMENTS=2>
anotherkey
key3

To compare a hash and a value:

hash = HASH('key1', 1.414, 'key2', 3.14, 'key3', 1.414)
result = hash NE 1.414    ; (or 1.414 NE hash)
HELP, result
PRINT, result

IDL Prints:

RESULT          LIST  <ID=114857  NELEMENTS=1>
key2

To compare a hash and a !NULL value:

hash = HASH('key1', 1.414, 'key2', 3.14, 'key3', !NULL, 'key4', !NULL)
result = hash NE !NULL    ; (or !NULL NE hash)
HELP, result
PRINT, result

IDL Prints:

RESULT          LIST  <ID=114817  NELEMENTS=2>
key2
key1

Hash Access


In many cases, you can access elements of a hash variable using standard IDL array syntax, as if the hash were a one-dimensional array.

Retrieve a Single Element

To copy the value of a single hash element into a new variable, leaving the hash unchanged, use array syntax:

value = hash[Key]

where Key is the scalar key of the desired element within the hash.

To retrieve an arbitrary element in a hash and remove it, use the hash.Remove() method:

value = hash.Remove()

To retrieve a specific element in a hash and remove it:

value = hash.Remove(Key)

where Key is the scalar key of the desired element within the hash.

Insert a Single Element

To insert a single value into a hash, creating a new hash element, use array syntax:

hash[Key] = Value

where Value is the value to be stored in the new hash element.

Change the Value of a Single Element

To change the value of a single hash element, use array syntax:

hash[Key] = Value

where Key is the scalar key of the desired element within the hash and Value is the new value.

Retrieve Multiple Elements and Create a New Hash

To create a new hash that is a subset of an existing hash, use array syntax:

newHash = origHash[ Keys ]

where Keys is an array or list of keys. Here newHash is a new hash variable that contains copies of the key-value pairs from origHash.

Insert or Change the Value of Multiple Elements

Insert or change the value of multiple hash elements in a single operation by specifying an array or list of keys to be replaced and/or added in the existing hash and providing the replacement values in an array or list:

hash[ Keys ] = Values

where Keys is an array or list of keys, and Values is a scalar, an array or a list of values. If Values is a scalar, then that value is copied into every key. Otherwise, if Values is an array or a list, it must contain the same number of elements as the keys. In this case each element of Keys and Values is inserted as a separate key-value pair. For each key-value pair, if the key already exists in the hash then the value is replaced, and if the key does not exist then it is added. If a given key occurs more than once within the new keys, the last value will be retained.

Copy a Hash

To copy a hash reference, assign it to a new variable:

newHash = origHash

It is important to understand that with this operation, newHash and origHash are references to the same hash; modifying an element in one hash modifies the same element in the other hash. For example, if we create hash2 as a copy of hash1 and then change the value of an element in hash2, the same element in hash1 also changes:

hash1 = HASH('key1', 1, 'key2', 2)
hash2 = hash1
hash2['key1'] = 'hello'
HELP, hash1['key1'], hash2['key1']

IDL Prints:

<Expression>    STRING    = 'hello'
<Expression>    STRING    = 'hello'

Note that both hashes contain the new value for that key.

To create a new hash variable whose elements are copies of the values in the original hash, you could use the following:

newHash = HASH(origHash.Keys(), origHash.Values())

Another method to copy a hash is to use array syntax to copy all of the elements:

newHash = origHash[*]

For example:

hash1 = HASH('key1', 1, 'key2', 2)
hash2 = hash1[*]
hash2['key1'] = 'hello'
HELP, hash1['key1'], hash2['key1']

IDL Prints:

<Expression>    STRING    = 1
<Expression>       STRING    = 'hello'

Note that the value in hash1 remains unchanged.

Iterate Through a Hash

To iterate through the elements in a hash, loop over the keys and use standard array syntax:

hash = HASH('Mercury', 1, 'Venus', 2, 'Earth', 3, 'Mars', 4)
keys = hash.Keys()
FOR i=0,N_ELEMENTS(hash)-1 DO PRINT, hash[keys[i]]

A more efficient method of iteration is to use FOREACH:

  hash = HASH('Mercury', 1, 'Venus', 2, 'Earth', 3, 'Mars', 4)
  FOREACH value, hash DO            PRINT, 'Value = ', value

You may also use the optional argument to FOREACH to retrieve the key associated with each value:

  hash = HASH('Mercury', 1, 'Venus', 2, 'Earth', 3, 'Mars', 4)
  FOREACH value, hash, key DO PRINT, key + ' is planet #', value
 

Note: While iterating through a hash avoid adding or removing elements. If the hash is changed during the FOREACH, the behavior is undefined.

Access and Change Array Elements within a Hash

If a hash item contains an array, another hash, or a list, individual elements within that item may be accessed and modified using standard array syntax. In this case, the first dimension must be a hash key (a scalar string or number) that specifies the hash element, and the higher dimensions are used to index into the array itself. The higher dimensions may be any combination of scalars, subscript ranges, or index arrays. The syntax looks like:

values = hash[key, sub0, sub1,...]
hash[key, sub0, sub1,...] = values

where key is a scalar string or number that specifies the hash element, and sub0, sub1,... are the subscript ranges or indices for the contained array.

For example, to create a "ragged" array, where each element is a vector of a different length:

hash = HASH( 'Array1', FINDGEN(100), 'Array2', FINDGEN(67), 'Array3', FINDGEN(93), $
 'Array4', FINDGEN(120) )
 
; Print the 6th element of the first vector
PRINT, hash['Array1', 5]
 
; Print every other element of the third vector
PRINT, hash['Array3', 0:*:2]
 
; Change several elements of the fourth vector
HASH['Array4', [5,10,15,20]] = -1

In this example, we create a hash that contains a one-dimensional array, a string, and a two-dimensional array:

hash = HASH( 'Data', FINDGEN(10), 'Date', 'April 1, 2001', 'Hanning', HANNING(100, 50) )
 
; Modify an element in the center of the 2D array
hash['Hanning', 50, 25] = 0.0
 
; Change an entire column of the 2D array
hash['Hanning', 99, *] = -1.0
 
; Extract a subset of the 2D array
HELP, hash['Hanning', 10:15, 7:11]

IDL prints:

<Expression>    FLOAT     = Array[6, 5]

In this example, we create a hash that contains a one-dimensional array, a string, a list, (which contains a two-dimensional array), and another hash:

hash = HASH('Data', FINDGEN(10), 'Date', 'April 2', $
  'List', LIST('MyData', DIST(20, 30)), $
  'Properties', HASH('LINESTYLE', 3, 'THICK', 2) )
 
; Extract the entire 2D array from the sub-list
HELP, hash['List', 1]
 
; Extract a subset of the 2D array within the sub-list
HELP, hash['List', 1, 10:15, [20,21,22] ]
 
; Add a new key-value to the hash within the hash
hash['Properties', 'COLOR'] = 'blue'
 
; Extract a value from the hash within the hash
HELP, HASH['Properties', 'COLOR' ]

IDL prints:

<Expression>    FLOAT     = Array[20, 30]
<Expression>    FLOAT     = Array[6, 3]
<Expression>    STRING    = 'blue'

Note: When indexing into an array contained within a hash, the first dimension must always be the hash key. Since IDL can only handle a maximum of eight dimensions, you can only use up to seven dimensions when indexing into an array within a hash. If the array is contained within a hash or list (which is itself contained within a hash), the maximum number of dimensions will be six, and so on.

Auto-Instantiation of Nested Hash Elements

Imagine that we create a nested hash:

h = HASH('a', HASH('b', HASH('c', 5)))

We can then access our nested value using multiple-array subscripts:

PRINT, h['a', 'b', 'c']

We could also have created the nested hash using multiple statements:

h = HASH()
h['a'] = HASH()
h['a', 'b'] = HASH()
h['a', 'b', 'c'] = 5

Both of the above methods are cumbersome and error prone. Instead, just like inserting an unknown hash key will add that hash key, we can also nest "unknown" subscripts and IDL will create the necessary nested hash. For example:

h = HASH()
h['a', 'b', 'c'] = 5
PRINT, h, /IMPLIED

IDL prints:

{
  "a": {
    "b": {
      "c": 5
    }
  }
}

Note: If your object is a subclass of hash, such as an ORDEREDHASH or a DICTIONARY, then IDL will actually create a nested container of that same subclass.

Information about Hashes


Logical Truth

The logical truth operator evaluates a hash. It returns a value of 1 (TRUE) if the hash is non-empty, and returns 0 (FALSE) if the hash is empty.

IF (hash) THEN . . .

Logical Negation

The logical negation operator negates the logical value of a hash:

IF (~hash) THEN . . .

If hash is TRUE, the statement evaluates as FALSE, and so on.

N_ELEMENTS

The N_ELEMENTS function returns the number of elements in a hash:

Result = N_ELEMENTS(hash)

If hash contains zero elements, or if hash is an undefined variable, 0 is returned.

For more information, see N_ELEMENTS.

ISA

The ISA function can determine whether the given variable is a hash:

x = HASH('key1', 1, 'key2', 2)
PRINT, ISA(x, 'HASH')

IDL prints:

1

For more information, see ISA.

TYPENAME

The TYPENAME function returns the type HASH for a hash variable:

x = HASH('key1', 1, 'key2', 2)
PRINT, TYPENAME(x)

IDL prints:

HASH

For more information, see TYPENAME.

HELP

The HELP procedure provides general information about a hash variable:

newHash = HASH('key1', 1, 'key2', [1,2,3])
HELP, newHash

IDL prints:

NEWHASH         HASH  <ID=1 NELEMENTS=2>

In this case, the variable name is NEWHASH. the type name is HASH, the heap ID is 1, and there are two elements in the hash.

PRINT

The PRINT procedure gives the value for each hash element:

newHash = HASH('Mercury', 1, 'Venus', 2, 'Earth', 3, 'Mars', 4)
PRINT, newHash

IDL prints:

Earth, 3
Mars, 4
Venus, 2
Mercury, 1

Implied Print

Using Implied Print with a hash will print out the hash key/values in standard JSON notation. For example, enter the following lines at the IDL command prompt:

img = HASH()
img["src"] = "Images/Sun.png"
img["name"] = "sun1"
img["hOffset"] = LIST(250, 500, 1000)
img["alignment"] = "center"
newHash = HASH()
newHash["image"] = img
newHash

IDL prints:

{
  "image":
  {
    "src":          "Images/Sun.png",
    "name":         "sun1",
    "hOffset":
    [
      250,
      500,
      1000
    ],
    "alignment":    "center"
  }
}

Tip: You can also output a hash in YAML notation using YAML_SERIALIZE.

Version History


8.0

Introduced

8.1

Added NO_COPY keyword to ToStruct function method

Added Count, FindValue, IsEmpty methods

Added ability to index into arrays within a hash

8.2 Added the Where method, deprecated the FindValue method
8.3 Added Implied Print to JSON format
8.4 Added FOLD_CASE keyword
8.5 Added auto-instantiation of nested hash elements
8.5.1 Added IsFoldCase method
8.8.1

Ported from PRO code to C++ for performance.

See Also


!NULL, DICTIONARY, LIST, ORDEREDHASH, Logical Operators, Relational Operators