I wonder if there is a less verbose way than using a loop. Anyway this works for me in CLISP:
(loop for key being the hash-keys of *my-hash* collect key)
I've seen others using maphash
, but that involves accumulating each key into a list. Apart from that being more involved than using loop, it also introduces a side-effect, which I try to avoid whenever I can - I prefer functional programming as much as possible :)
Is there anything predefined like this for this common task, even though implementation-specific?
(defun hash-keys (hash-table) (loop for key being the hash-keys of hash-table collect key))
Common Lisp comes from before "batteries-included" philosophy became prevalent, and most functionality is expected to be provided by third-party libraries and not implementations. While Common Lisp is sometimes called a large language, it is only compared to C and similar, the language itself is quite tiny compared to Python and other languages with massive standard libraries.
For this specific purpose, Alexandria is a commonly used collection of Common Lisp utilities. Among many other things it contains hash-table-keys
.
There is no disadvantage in defining
(defun hash-keys (hash-table) (loop for key being the hash-keys of hash-table collect key))
because in Common Lisp the function is compiled. If your vendor provided this function, it would pretty much do the same thing and not be much more efficient than yours, if at all.
In interpreted languages, nearly anything you write yourself has a performance disadvantage compared to an "intrinsic" routine.
Consing up the contents of a hash is wasteful; loop lets you process the hash without consing up memory. So maybe you want a macro instead (Some Lisps provide a dohash
or similar as an extension).
(defmacro do-hash ((key-var val-var hash-expr &optional result-form) &body body) (let ((hash-var (gensym "HASH-"))) `(loop with ,hash-var = ,hash-expr for ,key-var being the hash-keys of ,hash-var for ,val-var being the hash-values of ,hash-var do (progn ,@body) finally (return ,result-form))))
Or a hash mapping function:
(defun mapc-hash (hash-table fun) (loop for key being the hash-keys of hash-table for value being the hash-values of hash-table do (funcall fun key value)))
Should the language have every possible gadget like this that anyone can write in a minute?
In Common Lisp, there are included batteries, but they are other kinds of batteries: things that are actually hard to do. For example, a compile
function for dynamically compiling code at run time. It would be prohibitively difficult for most users to develop such a thing from scratch compared to pulling keys or values from a hash table in half a dozen different ways.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With