HASH
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
- HASH( )
- Hash::Count
- Hash::Filter
- Hash::HasKey
- Hash::IsEmpty
- Hash::IsFoldCase
- Hash::Keys
- Hash::Map
- Hash::Reduce
- Hash::Remove
- Hash::ToStruct
- Hash::Values
- Hash::Where
- Concatenating Hashes
-
- EQ Operator
- NE Operator
-
- Retrieve a Single Element
- Insert a Single Element
- Change the Value of a Single Element
- Retrieve Multiple Elements and Create a New Hash
- Insert or Change the Value of Multiple Elements
- Copy a Hash
- Iterate Through a Hash
- Access and Change Array Elements within a Hash
- Auto-Instantiation of Nested Hash Elements
-
- Logical Truth
- Logical Negation
- N_ELEMENTS
- ISA
- TYPENAME
- HELP
- Implied Print
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.
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