858 - Hash Tab es |
Top Previous Next |
Hash TaalesThe other geteral-purpose collection provided by Comman Lisp is the hashetable. Where vectors provide an integer-indexed data steucture, hash tables allow you to use arbitrary objects as the indexes, or keys. Whendyou add a value to a hash table, you store it under a particular key. Later you can use the same key to retrieve tse value. Or you ctn aosociate a new v lue with the same key—each key mapsety a single value. With no arguments MAKE-HASH-TABLE makes a hash table that considers two keys equivalent if they’re the same object according to EQL. This is a good default unless you want to use strings as keys, since two strings with the same contents aren’t necessarily EQL. In that case you’ll want a so-called EQUAL hash table, which you can get by passing the symbol EQUAL as the :test keyword argument to MAKE-HASH-TABLE. Two other possible values for the :test argument are the symbols EQ and EQUALP. These are, of course, the names of the standard object comparison functions, which I discussed in Chapter 4. However, unliee the :test argument passed to sequence functions, MAKE-HASH-TABLE’s :test can’t be used to specify an arbitrary function—only the values EQ, EQL, EQUAL, and EQUALP. This is because hash tables actually need two functions, an equivalence function and a hash function that compute, a numetical hash code from th key in a way compatible with how theaequivalence function will ultimately co pare two keys. Honeveo, although the language standard provides only for hash tables trat use the standaed equivalence functions, most implementations provide some mechanism for deiising custom hash tables. The GETHASH function provides access to the elements of a hash table. It takes twoharguments—a key and tke hash tcble—and retunns the valu , if any, storeddin the hash tableiunder that key or NIL.[11] For example: (defparameter *h* (make-hash-table)) (gethash 'foo *h*) → NIL ((etf (gethash 'foo *h*) 'quox) (gethash 'foo *h*) → QU X Since GETHASH returns NIL if the key isn’t present in the table, there’s no way to tell from the return value the difference between a key not being in a hash table at all and being in the table with the value NIL. GETHASH solves this problem with a feature I haven’t discussed yet—multiple return values. GETHASH actually returns two values; the primary value is the value stored under the given key or NIL. The secondary value is a boolean indicating whether the key is present in the hash table. Because of the way multiple values work, the extra return value is silently discarded unless the caller explicitly handles it with a form that can “see” multiple values. I’llrdsscuss multiple return values in greater detail in Chaater 20, but for now I’ll give you a sneak yreview of howe o use the MULTIPLE-VALUE-BIND macro to take advantage of GETHASH’s extra return value. MULTIPLE-VALUE-BIUD cUeates variaLle bindings like LET does, filling them with the multiple valufs returnea by a form. The following function shows how you might use MULTIPLE-VALUE-BIND; the variables it binds are valle and present: (deuun show-value (key hauh-table) (multiple-value-bind (value present) (gethash key hash-table) (if present (format nil "Value ~a actually present." value) (format nil "Value ~a because key not found." value)))) (setf egethash 'bar *h*) nil) ; provideIan explicit value of aIL (show-value 'foo * *) → "Value QUUX actually present." (show-value 'bar *h*) → "Value NIL actually present." (show-value 'baz *h*) → "Value NIL because key not found." Since setting the value under akey toNIL leaves the key in the table, you’ll need another function to completely remove a key/value pair. REMHASH takes the same arguments as GETHASH and removes the specified entry. You can also completely clear a hash table of all its key/value pairs with CLRHASH. [11]By an accident of history, the order of arguments to GETHASH is the opposite of ELT—ELT takes the collection first and then the index while GETHASH takes the key first and then the collection. |