如何在common-lisp的循环中执行两个或更多指令?

时间:2016-09-06 20:08:04

标签: loops common-lisp hashtable nested-loops

我想知道这段代码有什么问题.Assume *语料库是一个单词列表(“at”“the”...),这段代码试图将它们保存在哈希表中(字时间重复) -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)))

如果单词在哈希表中只增加1,则添加一对新词。

2 个答案:

答案 0 :(得分:4)

你想迭代一个单词集;对于每个单词 w ,如果 w 在某个散列中映射到整数 n ,则需要递增该数字以便 w 映射到 n + 1 ;否则,您要将该单词映射为1。

基本上,你想这样做:

(defun increment-corpus (corpus hash)
  (map nil
       (lambda (word)
         (incf (gethash word hash 0)))
       corpus))
  • 我正在使用MAP,以便我可以迭代任何单词序列,而不仅仅是列表。

  • MAP的结果类型为NIL,因为我不关心结果,我只是想制造副作用。

  • 应用的函数只会增加绑定到word的当前值。请注意,GETHASH提供了一个默认表单,以便在没有值绑定到给定键的情况下进行评估。在这里,我只需要设置零,以便增量适用于所有情况。我起初并没有读过它,但来自Terje D.的this comment已经说过了。

实施例

(defparameter *hash* (make-hash-table :test #'equal))

(defun test (&rest words)
  (increment-corpus words *hash*)
  (maphash (lambda (&rest entry) (print entry)) *hash*))

哈希最初是空的。

> (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) 

答案 1 :(得分:3)

CL中的块看起来像这样:

(progn
  expression1
  expression2
  ...
  expressionn); the result of the form is result of expressionn

这可以用于需要一个表达式的地方,因为块是一个表达式。在循环do之后可以跟一个或多个复合形式(函数调用,宏调用,特殊形式......):

(loop :for element :in list
      :do expression1
          expression2
          expression3)