I would like to know whats wrong with this code.Assume *corpus is a list of words ("at" "the" ...) and this code tries to keep them in a hash-table (word times-repeated-word)
(defparameter h (make-hash-table))
(defparameter ex 0)
(loop for x in *corpus
do ((setf ex 0)
(loop for y being the hash-keys of h
if (equal x y) do ((incf (gethash y h)) (setf ex 1)))
if (eql ex 0)
do (setf (gethash x h) 1)))
If the word is in the hash-table just increase 1, else add a new pair.
You want to iterate over a corpus of words; for each word w, if w is mapped to an integer n in some hash, you want to increment that number so that w is mapped to n+1; otherwise, you want to map that word to 1.
Basically, you want to do this:
(defun increment-corpus (corpus hash)
(map nil
(lambda (word)
(incf (gethash word hash 0)))
corpus))
I am using MAP
so that I can iterate over any sequence of words, not just lists.
The result-type of MAP
is NIL
, because I don't care about the result, I just want to make side-effects.
The function that is applied simply increments the current value bound to word
. Note that GETHASH
provides a default form to be evaluated in case no value is bound to the given key. Here, I just need to put zero so that the increment works in all cases. I didn't read it at first, but this comment from Terje D. already said it.
(defparameter *hash* (make-hash-table :test #'equal))
(defun test (&rest words)
(increment-corpus words *hash*)
(maphash (lambda (&rest entry) (print entry)) *hash*))
The hash is initially empty.
> (test "a" "b" "c" "d")
("a" 1)
("b" 1)
("c" 1)
("d" 1)
> (test "a")
("a" 2)
("b" 1)
("c" 1)
("d" 1)
> (test "a" "b" "c" "x")
("a" 3)
("b" 2)
("c" 2)
("d" 1)
("x" 1)