Common lisp 用公共lisp实现词典

Common lisp 用公共lisp实现词典,common-lisp,Common Lisp,我正在尝试使用CommonLisp中的列表实现一个字典。该程序应该获取一个单词列表,并创建一个单词直方图,其中包含每个唯一单词的频率 以下是节目: (defparameter *histo* '()) (defun scanList (list) (loop for word in list do (if (assoc word histo) ((setf pair (assoc word histo)) (remove pair

我正在尝试使用CommonLisp中的列表实现一个字典。该程序应该获取一个单词列表,并创建一个单词直方图,其中包含每个唯一单词的频率

以下是节目:

(defparameter *histo* '())

(defun scanList (list)
  (loop for word in list
     do (if (assoc word histo)
            ((setf pair (assoc word histo))
             (remove pair histo)
             (setf f (+ 1 (second pair)))
             (setf pair ((car pair) f))
             (append histo pair))
            ((setf pair (word '1)) (append histo pair)))))
我得到的错误是:
(SETF对(ASSOC-WORD*HISTO*)应该是lambda表达式

语法或语义错误到底在哪里

(defun scanList (list the fox jumped over the other fox))
(princ *histo*)

发布的代码有很多问题。报告的错误是由多余的括号引起的。在Lisps中,不能随意将括号添加到表达式中而不会引起问题。在这种情况下,以下是令人不快的表达:

((setf pair (assoc word histo))
 (remove pair histo)
 (setf f (+ 1 (second pair)))
 (setf pair ((car pair) f)
 (append histo pair))

((setf pair (word '1)) (append histo pair))
在这两个表达式中,对
setf
的调用结果都放在列表的函数位置,因此代码试图调用该结果,就像调用函数一样,从而导致错误

还有其他问题。看起来OP-code试图将表达式打包到
if
表单的臂弯中;这可能是上述附加括号的来源。但是,
if
表单只能在每个手臂中使用一个表达式。您可以将多个表达式包装在
progn
表单中,或者改用
cond
(这允许在每个arm中使用多个表达式)。有一些打字错误:
*histo*
在大多数代码中被误键入
histo
f
在任何地方都没有定义
(setf pair(单词“1”)
不必要地引用
1
(这会起作用,但在语义上是错误的)

总之,代码看起来相当复杂。这可以简单得多,但仍遵循相同的基本思想:

(defparameter *histo* '())

(defun build-histogram (words)
  (loop :for word :in words
        :if (assoc word *histo*)
          :do (incf (cdr (assoc word *histo*)))
        :else
          :do (push (cons word 1) *histo*)))
这段代码几乎是不言自明的。如果一个
单词
已经添加到
*histo*
,则增加其计数器。否则,添加一个计数器初始化为1的新条目。这段代码并不理想,因为它使用一个全局变量来存储频率计数。更好的解决方案是构建一个新的频率计数列表,并返回:

(defun build-histogram (words)
  (let ((hist '()))
    (loop :for word :in words
          :if (assoc word hist)
            :do (incf (cdr (assoc word hist)))
          :else
            :do (push (cons word 1) hist))
    hist))

当然,您可以通过各种其他方式来解决这个问题。

发布的代码有很多问题。报告的错误是由多余的括号引起的。在Lisps中,不能随意将括号添加到表达式中而不会引起问题。在这种情况下,以下是令人不快的表达:

((setf pair (assoc word histo))
 (remove pair histo)
 (setf f (+ 1 (second pair)))
 (setf pair ((car pair) f)
 (append histo pair))

((setf pair (word '1)) (append histo pair))
在这两个表达式中,对
setf
的调用结果都放在列表的函数位置,因此代码试图调用该结果,就像调用函数一样,从而导致错误

还有其他问题。看起来OP-code试图将表达式打包到
if
表单的臂弯中;这可能是上述附加括号的来源。但是,
if
表单只能在每个手臂中使用一个表达式。您可以将多个表达式包装在
progn
表单中,或者改用
cond
(这允许在每个arm中使用多个表达式)。有一些打字错误:
*histo*
在大多数代码中被误键入
histo
f
在任何地方都没有定义
(setf pair(单词“1”)
不必要地引用
1
(这会起作用,但在语义上是错误的)

总之,代码看起来相当复杂。这可以简单得多,但仍遵循相同的基本思想:

(defparameter *histo* '())

(defun build-histogram (words)
  (loop :for word :in words
        :if (assoc word *histo*)
          :do (incf (cdr (assoc word *histo*)))
        :else
          :do (push (cons word 1) *histo*)))
这段代码几乎是不言自明的。如果一个
单词
已经添加到
*histo*
,则增加其计数器。否则,添加一个计数器初始化为1的新条目。这段代码并不理想,因为它使用一个全局变量来存储频率计数。更好的解决方案是构建一个新的频率计数列表,并返回:

(defun build-histogram (words)
  (let ((hist '()))
    (loop :for word :in words
          :if (assoc word hist)
            :do (incf (cdr (assoc word hist)))
          :else
            :do (push (cons word 1) hist))
    hist))

当然,还有其他各种方法可以解决这个问题。

使用哈希表创建字典,然后转换为关联列表(alist)以按键或值排序

(defun build-histo (l)
  (let ((dict (make-hash-table :test 'equal)))
    (loop for word in l
          do (incf (gethash word dict))
          finally (return dict))))

;; which was simplification (by @Renzo) of
;; (defun build-histo (l)
;;   (let ((dict (make-hash-table :test 'equal)))
;;     (loop for word in l
;;           for count = (1+ (gethash word dict 0))
;;           do (setf (gethash word dict) count)
;;           finally (return dict))))

(defparameter *histo* (build-histo '("a" "b" "c" "a" "a" "b" "b" "b")))

(defun hash-table-to-alist (ht)
  (maphash #'(lambda (k v) (cons k v)) ht))

;; which is the same like:
;; (defun hash-table-to-alist (ht)
;;   (loop for k being each hash-key of ht
;;         for v = (gethash k ht)
;;         collect (cons k v)))


;; sort the alist ascending by value
(sort (hash-table-to-alist *histo*) #'< :key #'cdr)
;; => (("c" . 1) ("a" . 3) ("b" . 4))

;; sort the alist descending by value
(sort (hash-table-to-alist *histo*) #'> :key #'cdr)
;; => (("b" . 4) ("a" . 3) ("c" . 1))

;; sort the alist ascending by key
(sort (hash-table-to-alist *histo*) #'string< :key #'car)
;; => (("a" . 3) ("b" . 4) ("c" . 1))

;; sort the alist descending by key
(sort (hash-table-to-alist *histo*) #'string> :eky #'car)
;; => (("c" . 1) ("b" . 4) ("a" . 3))
(定义构建历史(l)
(let((dict(使哈希表:test'equal)))
(循环表示l中的单词
do(incf(gethash单词dict))
最后(返回dict)))
;; 这是简化(由@Renzo)的
;; (除建造历史(左)
;;;(让((dict(使哈希表:test'equal))相等)
(l中单词的循环
;对于计数=(1+(gethash单词dict 0))
;do(setf(gethash单词dict)计数)
最后(返回命令)
(defparameter*histo*(构建历史’(“a”“b”“c”“a”“a”“b”“b”))
(将哈希表定义为列表(ht)
(maphash#’(lambda(k v)(cons k v))ht)
;; 这是一样的:
;; (将哈希表定义为列表(ht)
;(k为ht的每个散列键的循环)
;对于v=(gethash k ht)
收集(cons k v)))
;; 按值对列表进行排序
(排序(哈希表到列表*历史*)#'<:key#'cdr)
;; => (“c.1”(“a.3”(“b.4))
;; 按值对列表进行排序
(排序(哈希表到列表*历史*)#'>:key#'cdr)
;; => (“b.4”(“a.3”(“c.1))
;; 按键对列表进行排序
(排序(哈希表到列表*历史*)#字符串<:key#car)
;; => (“a.3”(“b.4”(“c.1))
;; 按键对列表进行排序
(排序(哈希表到列表*历史*)#'字符串>:eky#'car)
;; => (“c.1”(“b.4”(“a.3))

使用哈希表创建字典,然后转换为关联列表(alist)以按键或值对其进行排序

(defun build-histo (l)
  (let ((dict (make-hash-table :test 'equal)))
    (loop for word in l
          do (incf (gethash word dict))
          finally (return dict))))

;; which was simplification (by @Renzo) of
;; (defun build-histo (l)
;;   (let ((dict (make-hash-table :test 'equal)))
;;     (loop for word in l
;;           for count = (1+ (gethash word dict 0))
;;           do (setf (gethash word dict) count)
;;           finally (return dict))))

(defparameter *histo* (build-histo '("a" "b" "c" "a" "a" "b" "b" "b")))

(defun hash-table-to-alist (ht)
  (maphash #'(lambda (k v) (cons k v)) ht))

;; which is the same like:
;; (defun hash-table-to-alist (ht)
;;   (loop for k being each hash-key of ht
;;         for v = (gethash k ht)
;;         collect (cons k v)))


;; sort the alist ascending by value
(sort (hash-table-to-alist *histo*) #'< :key #'cdr)
;; => (("c" . 1) ("a" . 3) ("b" . 4))

;; sort the alist descending by value
(sort (hash-table-to-alist *histo*) #'> :key #'cdr)
;; => (("b" . 4) ("a" . 3) ("c" . 1))

;; sort the alist ascending by key
(sort (hash-table-to-alist *histo*) #'string< :key #'car)
;; => (("a" . 3) ("b" . 4) ("c" . 1))

;; sort the alist descending by key
(sort (hash-table-to-alist *histo*) #'string> :eky #'car)
;; => (("c" . 1) ("b" . 4) ("a" . 3))
(定义构建历史(l)
(let((dict(使哈希表:test'equal)))
(循环表示l中的单词
do(incf(gethash单词dict))
最后(返回dict)))
;; 这是简化(由@Renzo)的
;; (除建造历史(左)
;;;(让((dict(使哈希表:test'equal))相等)
(l中单词的循环
;对于计数=(1+(gethash单词dict 0))
;do(setf(gethash单词dict)计数)
最后(返回命令)
(defparameter*histo*(构建历史’(“a”“b”“c”“a”“a”“b”“b”))
(defun hash-table-t)