14
$\begingroup$

Lacking from the simple API of System`Utilities`HashTable is a method to enumerate the keys/values.

?System`Utilities`Hash*

HashTable   HashTableAdd    HashTableContainsQ  HashTableGet    HashTableRemove

After creating a hash table

h = System`Utilities`HashTable[];
System`Utilities`HashTableAdd[h, "a", 1];

Various methods to extract its content fail.

h[[1]]
h
DownValues[h]

Any way out?

$\endgroup$
  • 1
    $\begingroup$ I wonder what HashTableGet[] does... :) $\endgroup$ – J. M. is away Jun 8 '13 at 15:17
  • $\begingroup$ @J. M. I think OP wants to list all available key-value pairs in the table, which I believe is not possible. $\endgroup$ – rm -rf Jun 8 '13 at 15:21
  • 2
    $\begingroup$ If you want to be able to enumerate the contents, you're probably better off just to use ordinary downvalues rather than the System`Utilities`HashTable. $\endgroup$ – Oleksandr R. Jun 8 '13 at 19:44
  • $\begingroup$ Just to follow up on J. M., you have tried System`Utilities`HashTableGet[h, "a"]? $\endgroup$ – Seth Chandler Jun 9 '13 at 5:35
12
$\begingroup$

I'm sure there must be a better way, but this works:

h = System`Utilities`HashTable[];
System`Utilities`HashTableAdd[h, "a", 1];
System`Utilities`HashTableAdd[h, "b", 2];

ToExpression[ToString[h, InputForm], InputForm, Hold][[1, 2]]
{{"a", 1}, {"b", 2}}

Mr. Wizard provides a more terse version:

ToHeldExpression[ToString[h, InputForm]][[1, 2]]
$\endgroup$
  • $\begingroup$ Unless there is something like SparseArray[. . .]["NonzeroPositions"] for HashTable there very well may not be a better way. $\endgroup$ – Mr.Wizard Jun 9 '13 at 13:48
  • $\begingroup$ More terse: ToHeldExpression[ToString[h, InputForm]][[1, 2]] $\endgroup$ – Mr.Wizard Jun 9 '13 at 14:55
  • 1
    $\begingroup$ As with many things Mathematica I learned it from Leonid. It's an old function but still entirely, well, functional. $\endgroup$ – Mr.Wizard Jun 10 '13 at 10:13
  • 1
    $\begingroup$ +1. I still hope there is some more robust way though, since ToString-ToExpression transformation is not always robust. $\endgroup$ – Leonid Shifrin Jun 10 '13 at 10:28
  • 1
    $\begingroup$ @Leonid for testing purposes can you give an example where Simon's method fails? $\endgroup$ – Mr.Wizard Jun 10 '13 at 12:01
11
$\begingroup$

OP's question

Updating this post, the set of functions related to HashTable is in version 10.2:

$ContextPath = Prepend[$ContextPath, "System`Utilities`"];
?*HashTable*

HashTable      HashTableContainsQ   HashTableMapAt    HashTableSet
HashTableAdd   HashTableGet         HashTableRemove 

and is extended in version 10.3 to:

?*HashTable*

HashTable             HashTableGet      HashTableRemove
HashTableAdd          HashTableKeys     HashTableSet
HashTableClone        HashTableMapAt    HashTableToAssociation
HashTableContainsQ    HashTableQ        HashTableValues

With 10.3, an easier way to extract keys/values, per OP's question, becomes available.

• Define a hash table and fill it in (10.2, 10.3):

h = HashTable[];
HashTableAdd[h, "g", 1]
HashTableAdd[h, "h", "hello"]

• Extract keys and values (10.3):

HashTableKeys[h]
HashTableValues[h]

(* {"h", "g"} *)
(* {"hello", 1} *)

• Make it an association (10.3) and use the functions Keys and Values:

asso = HashTableToAssociation[h]
(* <|"h" -> "hello", "g" -> 1|> *)

Keys[asso]
Values[asso]

(* {"h", "g"} *)
(* {"hello", 1} *)

What do other functions do?

This question has been covered to some extent in other posts (in particular, see the answer of Oleksandr R. in post #990). I recall below the definitions already addressed, and provide those that are new from 10.2.

HashTableSet changes the value of a key (10.2, 10.3):

HashTableSet[h, "h", "world"];
HashTableToAssociation[h]
(* <|"h" -> "world", "g" -> 1|> *)

HashTableRemove removes a pair key/value by referring to the key (10.2, 10.3):

HashTableRemove[h, "h"]
(* "world" *)

HashTableToAssociation[h]
(* <|"g" -> 1|> *)

HashTableGet gets the value of a key (10.2, 10.3):

HashTableGet[h, "g"]
(* 1 *)

HashTableContainsQ asks whether a key belongs to the hash table (10.2, 10.3):

HashTableContainsQ[h, "g"]
(* True *)

HashTableMapAt maps at a key a function on its associated value (10.2, 10.3):

HashTableToAssociation[h]
(* <|"g" -> 1|> *)

(* when existing *)
HashTableMapAt[h, "g", foo];
HashTableToAssociation[h]
(* <|"g" -> foo[1]|> *)

(* when not existing *)
HashTableMapAt[h, "h", "hello", "world"];
HashTableToAssociation[h]
(* <|"h" -> "hello"["world"], "g" -> foo[1]|> *)

HashTableClone clones a hash table and set it to a new one (10.3):

h2 = HashTableClone[h];
HashTableToAssociation[h2]
(* <|"h" -> "hello"["world"], "g" -> foo[1]|> *)

This function is particularly useful to avoid the following:

h3 = h;
HashTableToAssociation[h3]
(* <|"h" -> "hello"["world"], "g" -> foo[1]|> *)

HashTableAdd[h, "f", a]
HashTableToAssociation[h]
HashTableToAssociation[h2]
HashTableToAssociation[h3]

(* <|"f" -> a, "h" -> "hello"["world"], "g" -> foo[1]|> *)
(* <|"h" -> "hello"["world"], "g" -> foo[1]|> *)
(* <|"f" -> a, "h" -> "hello"["world"], "g" -> foo[1]|> *)

HashTableQ asks whether a given expression has a hash table structure (10.3):

HashTableQ[h2]
(* True *)

Hash tables and associations

Associations are introduced since version 10.0, so in principle one should prefer using them rather than hash tables. When there is a correspondence between an association function and a hash table function, the syntax of the former allows in general for more manipulations. Note also that more functions are available to manipulate associations.

Here is an equivalence between hash table and association functions (recall that "System`Utilities`" has been added in the context path):

(* Hash tables: *)    HashTableKeys
(* Associations: *)   Keys

(* Hash tables: *)    HashTableValues
(* Associations: *)   Values

(* Hash tables: *)    HashTableRemove
(* Associations: *)   KeyDrop

(* Hash tables: *)    HashTableGet
(* Associations: *)   Lookup, asso[key], asso[[Key[key]]]

(* Hash tables: *)    HashTableAdd
(* Associations: *)   Association[asso, key -> value]

(* Hash tables: *)    HashTableSet
(* Associations: *)   asso[key] = ..., asso[[Key[key]]] = ...

(* Hash tables: *)    HashTableClone
(* Associations: *)   asso1 = asso2

(* Hash tables: *)    HashTableContainsQ
(* Associations: *)   KeyExistsQ
$\endgroup$
  • $\begingroup$ Nice answer! Are you sure you want it to be a community wiki? It will probably get a fair number of votes. :-) $\endgroup$ – Mr.Wizard Feb 4 '16 at 14:22
  • $\begingroup$ I searched for documentation of HashTable functions on the web and on the help system of Mathematica 10.3. They are not documented, they exist only in System'Utilities. Is there any reason one should prefer to use HashTable instead of Association ? $\endgroup$ – Athanassios Aug 22 '16 at 8:00
  • $\begingroup$ @Athanassios (1/3) I would not recommend using HashTable instead of Association. The main reason is that, as you mentioned, the functions related to HashTable are not documented and not in System. So there is no guarantee that these functions won't change, or won't crash the kernel for some particular inputs. (I think these functions are robust, but this is always to keep in mind however for non-documented functions.) $\endgroup$ – user31159 Aug 22 '16 at 14:18
  • $\begingroup$ @Athanassios (2/3) Also because not documented, their behavior can be less predictable in appearance. Compare for instance the order of the key-value pairs of AssociationThread[# -> #] &[Range[10]] and h = HashTable[]; HashTableAdd[h, #, #] & /@ Range[10]; Through[{HashTableKeys, HashTableValues}[h]] on the one hand, and the order of the latter and g = HashTable[]; HashTableAdd[g, #, #] & /@ Range[100]; Through[{HashTableKeys, HashTableValues}[g]] on the other. If not careful about this, issues will occur for some types of processing done on the resulting expression. $\endgroup$ – user31159 Aug 22 '16 at 14:32
  • $\begingroup$ @Athanassios (3/3) About performance, the Association functions are highly optimized, so I don't think this should be a parameter to consider. At last, the Association framework contains more functions than the HashTable framework, so it will be possible to carry out more types of processing with associations. $\endgroup$ – user31159 Aug 22 '16 at 14:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.