Hi,
I'm currently trying to teach myself Lisp and am working my way through
Paul Graham's book. One of the exercises for chapter 4 asks the reader
to define a function that takes a hash table and returns a corresponding
assoc-list.
My attempt at an answer is as follows
(defun assoc-from-hash (ht)
(let ((assocList nil))
(maphash #'(lambda (k v)
(append assocList (list (cons k v)))) ht )
assocList))
I created a hash table as follows
(setf ht (make-hash-table))
(setf (gethash 'animal ht) 'dog)
(setf (gethash 'vegetable ht) 'carrot)
(setf (gethash 'mineral ht) 'zinc)
and when I call the function
(assoc-from-hash ht)
Lisp evaluates this as nil
What I'm trying to get is a list of the form
((ANIMAL . DOG) (VEGETABLE . CARROT) (MINERAL . ZINC))
but I can't get it to work.
The reason's probably something very simple but I can't see it. Can
anyone point out where I'm going wrong?
In case it's pertinent, I'm using CLISP 2.38 with SLIME on Windows XP.
Thanks,
Joe
--
Posted via a free Usenet account from http://www.teranews.com
You're misusing "append", in typical newbie fashion :-)
Try this:
(defun assoc-from-hash (ht)
(let ((assocList nil))
(maphash #'(lambda (k v)
(setf assocList (append assocList (list (cons k v))))) ht )
assocList))
The only difference is that I'm calling "setf" on the result of "append".
--
I shrivel inside each time [Star Wars] is mentioned.
-- Sir Alec Guinness
Eric Hanchrow wrote:
> You're misusing "append", in typical newbie fashion :-)
>
> Try this:
>
> (defun assoc-from-hash (ht)
> (let ((assocList nil))
> (maphash #'(lambda (k v)
> (setf assocList (append assocList (list (cons k v))))) ht )
> assocList))
>
> The only difference is that I'm calling "setf" on the result of "append".
Yeah, that works. Seems so obvious now :-)
Thanks,
Joe
--
Posted via a free Usenet account from http://www.teranews.com
"Joe Foran" <········@gmail.com> wrote in message
······························@free.teranews.com...
> Eric Hanchrow wrote:
>> You're misusing "append", in typical newbie fashion :-)
>>
>> Try this:
>>
>> (defun assoc-from-hash (ht)
>> (let ((assocList nil))
>> (maphash #'(lambda (k v)
>> (setf assocList (append assocList (list (cons k
>> v))))) ht )
>> assocList))
>>
>> The only difference is that I'm calling "setf" on the result of "append".
>
This algorithm will have very bad performances for a big hash-table as the
append function will need to run down the association list on each
iteration. I would use the loop facility, collecting the conses, or even
better just push the cons on the list as the order is not important (coming
from a hash-table anyways).
Sacha
Sacha <··@address.spam> wrote:
+---------------
| "Joe Foran" <········@gmail.com> wrote in message
| > Eric Hanchrow wrote:
| >> You're misusing "append", in typical newbie fashion :-)
| >> Try this:
...
| >> The only difference is that I'm calling "setf" on the result of "append".
|
| This algorithm will have very bad performances for a big hash-table as the
| append function will need to run down the association list on each
| iteration. I would use the loop facility, collecting the conses, or even
| better just push the cons on the list as the order is not important (coming
| from a hash-table anyways).
+---------------
Indeed. Here's my own personal convenience function for this:
(defun hash-table-alist (table &key (test (constantly t)))
(let (result)
(do-hash (key value table result)
(when (funcall test key value)
(push (cons key value) result)))))
In OP's case, he might not need the generality of the :TEST keyword, so:
(defun hash-table-alist (table)
(let (result)
(do-hash (key value table result)
(push (cons key value) result))))
One can also do it with LOOP [albeit with a somewhat awkward syntax]
this way:
(defun hash-table-alist (table)
(loop for key being the hash-keys in table
using (hash-value value)
collect (cons key value)))
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Rob Warnock wrote:
> Sacha <··@address.spam> wrote:
> +---------------
> | "Joe Foran" <········@gmail.com> wrote in message
> | > Eric Hanchrow wrote:
> | >> You're misusing "append", in typical newbie fashion :-)
> | >> Try this:
> ...
> | >> The only difference is that I'm calling "setf" on the result of "append".
> |
> | This algorithm will have very bad performances for a big hash-table as the
> | append function will need to run down the association list on each
> | iteration. I would use the loop facility, collecting the conses, or even
> | better just push the cons on the list as the order is not important (coming
> | from a hash-table anyways).
> +---------------
>
> Indeed. Here's my own personal convenience function for this:
>
> (defun hash-table-alist (table &key (test (constantly t)))
> (let (result)
> (do-hash (key value table result)
> (when (funcall test key value)
> (push (cons key value) result)))))
>
> In OP's case, he might not need the generality of the :TEST keyword, so:
>
> (defun hash-table-alist (table)
> (let (result)
> (do-hash (key value table result)
> (push (cons key value) result))))
>
What is DO-HASH?
(defun hash-table-to-alist (table)
(let (result)
(maphash (lambda (k v) (push (cons k v) result))
table)
result))
Bill Atkins <·········@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > (defun hash-table-alist (table)
| > (let (result)
| > (do-hash (key value table result)
| > (push (cons key value) result))))
|
| What is DO-HASH?
+---------------
Oops!! My bad. Sorry for not spotting that earlier.
It seems that DO-HASH is a CMUCL extension:
cmu> (describe 'do-hash)
DO-HASH is an external symbol in the EXTENSIONS package.
Macro-function: #<Byte function (:MACRO DO-HASH) {28F9EEE9}>
Macro documentation:
DO-HASH (Key-Var Value-Var Table [Result]) Declaration* Form*
Iterate over the entries in a hash-table.
...
that expands into a call of WITH-HASH-TABLE-ITERATOR, very
similar to the example definition of MAP-HASH in the CLHS
entry for WITH-HASH-TABLE-ITERATOR, except that instead of
FUNCALL'ing a function it executes a &BODY.
+---------------
| (defun hash-table-to-alist (table)
| (let (result)
| (maphash (lambda (k v) (push (cons k v) result))
| table)
| result))
+---------------
Yes, that's an equivalent standard-conformant way to define it.
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Joe Foran wrote:
> Hi,
>
> I'm currently trying to teach myself Lisp and am working my way through
> Paul Graham's book. One of the exercises for chapter 4 asks the reader
> to define a function that takes a hash table and returns a corresponding
> assoc-list.
>
> My attempt at an answer is as follows
>
> (defun assoc-from-hash (ht)
> (let ((assocList nil))
> (maphash #'(lambda (k v)
> (append assocList (list (cons k v)))) ht )
> assocList))
>
> I created a hash table as follows
>
> (setf ht (make-hash-table))
> (setf (gethash 'animal ht) 'dog)
> (setf (gethash 'vegetable ht) 'carrot)
> (setf (gethash 'mineral ht) 'zinc)
>
> and when I call the function
> (assoc-from-hash ht)
> Lisp evaluates this as nil
>
> What I'm trying to get is a list of the form
> ((ANIMAL . DOG) (VEGETABLE . CARROT) (MINERAL . ZINC))
> but I can't get it to work.
In MatzLisp or Ruby:
h = { :animal, :dog, :vegetable, :carrot, :mineral, :zinc }
h.to_a