Skip to content

2.7 Hashes

Juan Luis Gamero edited this page Dec 15, 2014 · 1 revision

2.7 Hash arrays

Harbour has native support for hash arrays (a.k.a. hash tables or associative arrays). It has it’s own type identifier (H) and a rich set of functions to operate on them. Additionally, you can access and assign values to hash arrays elements using arrays syntax, like this:

h := { "x" => 1, "y" => 3, "z" => 2 }

? h[ "x" ]         /* 1 */
? h[ "z" ]         /* 2 */
? h[ "y" ]         /* 3 */

h[ "y" ] := 128    /* Set 128 as the value assigned to key "y" */
Note

Harbour hash arrays can’t be considered pure "hash tables", as the order in wich the elements are stored can be determined, unlike pure "hash tables" where the order in wich elements are stored is irrelevant.

HB_Hash( <xKey1>, <xValue1> [ , <xKeyN>, <xValueN> ] ) → <hHash>

Creates a hash array and, optionally, populates it with elements (pairs of keys and values).

Note

It is recommended that a hash array is initialized using a literal ({ ⇒ }) instead of this function.

$TODO$ Find where this comes from to put a referente (I remember had read it but I can’t find right now)

HB_HHasKey( <hHash>, <xKey> [ , @<nPos> ] ) → <lExists>

Determines if a key exists in the hash and optionally gives its position. If the key doesn’t exists then <nPos> will be the position of the smaller nearest key.

HB_HGet( <hHash>, <xKey> ) → <uValue>

Gets the value associated to a key. See HB_HGetDef() if you don’t want a RTE when a value doesn’t exists.

HB_HGetDef( <hHash>, <xKey> [ , <xDefault> ] ) → <xValue>

Gets the value associated to a key or a default value if the key doesn’t exist. If a default value isn’t passed will return NIL.

HB_HGetRef( <hHash>, <xKey>, [ @<xValue> ] ) → <lFound>

Checks for the existence of a key and, at the same time, retrieving its corresponding value.

If the key is not found, <xValue> is also reset to NIL. Useful to replace HB_HPos()/HB_HValueAt() calls and temporary variables, or to avoid multiple hash lookups for the cost of one temporary variable.

HB_HSet( <hHash>, <xKey>, <xValue> ) → <hHash>

Sets the value associated to a key.

Important

<xValue> must be supplied. HB_HDefault() nor HB_HAutoAdd() won’t be taken in account.

HB_HDel( <hHash>, <xKey> ) → <hHash>

Deletes a key and it’s associated value from a hash.

HB_HPos( <hHash>, <xKey> ) → <nPos>

Gets the position of <xKey> in the hash.

HB_HKeyAt( <hHash>, <nPos> ) → <xKey>

Retrieves the key at a given position in a hash.

HB_HValueAt( <hHash>, <nPos> [ , <xNewValue> ] ) → <xValue>

Returns the value associated to the key at a given position in a hash. Optionally, you can set the new value <xNewValue> associated to the key at that position.

HB_HPairAt( <hHash>, <nPos> [ , <xNewKey>, <xNewValue> ] ) → ( <aKeyValue> | NIL )

Returns an array with the pair { key, value } at a given position in the hash. Optionally you can set the new key <xNewKey> and the value <xNewValue> in that position of the hash.

HB_HDelAt( <hHash>, <nPos> ) → <hHash>

Deletes the key and it’s associated value stored in the position <nPos> of the hash.

HB_HKeys( <hHash> ) → <aKeys>

Returns an array with all the keys (not the associated values) of a hash.

HB_HValues( <hHash> ) → <aValues>

Returns an array with all the associated values (not the keys) of a hash.

HB_HFill( <hHash>, <xValue> ) → <hHash>

Sets the values of all the keys in <hHash> to <xValue>.

HB_HClone( <hHash> ) → <hHashCopy>

Creates a copy of <hHash>.

HB_HCopy( <hSrcHash>, <hDstHash> [ , <nStart>, <nCount> ] ) → <hDstHash>

Copy elements from <hSrcHash> to <hDstHash>. You can specify the first element to copy in <nStart> and the number of elements to copy in <nCount>, otherwise all the elements will be copied.

HB_HMerge( <hDstHash>, <hSrcHash> [, <nMethod> := HB_HASH_UNION | <bBlock> ] ) → <hDstHash>

Merge two hashes. In the 3rd parameter you can specify the merge mode (see table bellow) or you can pass a codeblock that receives the key, the value and the position of each element of the <hSrcHash> hash array, and returs .T. if the element should be copied into <hDstHash>.

The predefined merge methods are (defined in hbhash.ch):

Constant Description

HB_MERGE_UNION

(DEFAULT) Copy elements that are in hSrcHash or in hDstHash (logical OR)

HB_MERGE_INTERSECT

Copy elements that are in both <hSrcHash> and <hDstHash> (logical AND)

HB_MERGE_XOR

Copy elements that don’t exists in both <hSrcHash> and <hDstHash> hashes (logical XOR)

HB_MERGE_REMOVE

Deletes from <hDstHash> the elements in <hSrcHash> that don’t exist in <hDstHash>

Note

Copied elements will substitute those with the same key in the destination hash.

HB_HClear( <hHash> ) → <hHash>

Deletes all the elements in <hHash> leaving an empty hash.

HB_HEval( <hHash>, <bBlock> [ , <nStart>, <nCount> ] ) → <hHash>

Evaluates a codeblock for each element of the hash. All the elements will be evaluated, but you can specify a starting element in <nStart> and the number of elements to be evaluated in <nCount>.

For each element evaluated, the key, the value and the position are passed to the codeblock.

HB_HScan( <hHash>, <uValue> | <bBlock> [ , <nStart>, <nCount> ], <lExact> ) → <hHash>

Scans the hash array values searching for <uValue> or you can pass a codeblock <bBlock> that receives the key, the value and the position of each element, and returs .T. if a match is found. You can limit the range of hash items to be scanned by the <nStart> and <nCount> parameters. If you set <lExact> to .T. and search for strings, datetime, array and hashes the value must be exactly equal to consider it found.

HB_HSort( <hHash> ) → <hHash>

Marks hash <hHash> for sorting. Binary and CaseMatch flags will affect the result.

HB_HAllocate( <hHash>, <nElements> ) → <hHash>

Pre-allocates space for <nElements> hash items. Useful when you are going to add a set of new items because you will save the time spent in grabbing each new element.

Note

Note that this function will not "truncate" or delete items in the hash if the <nElements> required are less that the actual item count in the hash.

Hash array flags

HB_HKeepOrder( <hHash> [ , <lKeepOrder> ] ) → <lPrevKeepOrder>

Sets the KEEPORDER flag in a hash and returns the previous state. This flag controls the order in wich elements are stored in the hash. If the KEEPORDER flag is .T. then the order in wich the elements are created or added will be preserved. If it is .F., then the elements of the hash will be sorted (other flags may affect the order such as the BINARY flag, the CASEMATCH flag, etc). This flag is enabled (.T.) by default.

HB_HCaseMatch( <hHash> [ , <lCaseMatch> ] ) → <lPrevCaseMatch>

Sets the CASEMATCH flag in a hash and returns the previous state. This flag controls the case sensitivity when you search or compare hash keys. By default, hash case matching flag is enabled (.T.).

HB_HBinary( <hValue> [ , <lBinary> ] ) → <lPrevBinary>

Sets the BINARY flag in a hash and returns the previous state. This flag controls when a binary comparison is done when searching and sorting strings. By default, this flag is enabled (.T.).

HB_HAutoAdd( <hHash>, [ <nAutoAdd> | <lAutoAdd>, <xDefault> ] ) → <nOldAutoAdd>

By default, when a hash array is created, the AUTOADD flag is enabled to assign operations (HB_HAUTOADD_ASSIGN), it means that every assign operation to a key that previously didn’t exist in the hash is automatically added, as in this example:

/*
   You will get Run Time Errors (RTE)
   Comment the offending line to see the rest of the test
*/

#include "hbhash.ch"

PROCEDURE Main()

   LOCAL h

   h := { => }         /* New empty hash */

   h[ 1 ] := "value"   /* auto-add key 1 */
   ? h[ 1 ]            /* => value */

   ? h[ 2 ]            /* => RTE. No auto-add on access */

   /* Now set auto-add on access (WARNING: but not on assign) */
   HB_HAutoAdd( h, HB_HAUTOADD_ACCESS, "[DEFAULT]" )

   ? h[ 3 ]            /* => [DEFAULT]  / NO RTE. Default value added on access */

   /* Now set new default value for auto-added elements */
   HB_HDefault( h, "[NEWITEM]" )

   ? h[ 4 ]            /* => [NEWITEM] */

   /* Don't auto-add in any case */
   HB_HAutoAdd( h, HB_HAUTOADD_NEVER )
   h[ 5 ] := "fail"    /* => RTE. No auto-add on assign */
   ? h[ 5 ]            /* => RTE. No keys auto-added, you must use HB_HSet() */

   RETURN

You can set the AUTOADD flags as a numeric value (defined in hbhash.ch) with the next options:

Constant Description

HB_HAUTOADD_NEVER

Clears the flag, and don’t automatically add keys in any case

HB_HAUTOADD_ACCESS

Auto-add keys on access operations

HB_HAUTOADD_ASSIGN

Auto-add keys on assign operations

HB_HAUTOADD_ALWAYS

Auto-add keys on access and assign operations (the same as HB_HAUTOADD_ACCESS + HB_HAUTOADD_ASSIGN)

If you pass the second parameter as a logical value, when you pass .T. it will set the AUTOADD flag to HB_HAUTOADD_ALWAYS if the hash has a default value assigned and it will set the flag to HB_HAUTOADD_ASSIGN if it has no default value assigned. In the other hand, if you pass .F. it will clear the flag (HB_HAUTOADD_NEVER).

You can, optionally, set the default value used when you add a key to a hash array with xDefault. This is useful to avoid subsequent HB_HDefault() calls.

This function returns the previous AUTOADD flag in as numeric value (see the HB_HAUTOADD_* table).

HB_HDefault( <hHash>, [ <xDefault> ] ) → <xPrevDefault>

Sets the default value assinged to new keys in a hash array. Specially useful when AUTOADD is enabled. You can set complex values as <xDefault> value and they will be cloned on new item addition. [1]

Examples: See example at HB_HAutoAdd()

Deprecated functions

The functions below are deprecated and marked as HB_LEGACY_LEVEL5.

Deprecated Instead use…​

HB_HSetAutoAdd()

HB_HAutoAdd()

HB_HSetCaseMatch()

HB_HCaseMatch()

HB_HSetBinary()

HB_HBinary()

HB_HSetOrder()

HB_HKeepOrder()

Clone this wiki locally