如何将值推送到哈希表中的现有列表中

Flu*_*lux 3 common-lisp

我正在尝试编写一个将数据添加到哈希表中的函数。该函数采用一个键和一个值。如果给定的键已存在于表中,则给定的值将附加到与该键关联的现有值中。如果表中尚不存在该键,则将该值放置在列表中并添加到表中。这是实现:

(defparameter *ht* (make-hash-table))

(defun add-to-table (key value)
  (multiple-value-bind (existing-values present-p) (gethash key *ht*)
    (if present-p
      (push value existing-values)
      (setf (gethash key *ht*) (list value)))))
Run Code Online (Sandbox Code Playgroud)

我尝试使用这样的函数:

(add-to-table 'company "Acme")
(add-to-table 'company "Ajax")
Run Code Online (Sandbox Code Playgroud)

然而,尽管我添加了两家公司,但(length (gethash 'company *ht*))返回1而不是。2这是为什么?

(push value existing-values)我发现用替换就可以解决问题(push value (gethash key *ht*))(gethash key *ht*)当我已经获得了它的值( )时,为什么还需要使用另一个existing-values?不应该existing-values是某种指向列表的指针吗?

Sva*_*nte 9

当您按下 时existing-values,您仅修改局部变量。

您可以通过使用单一形式的 place magic 来更简单地做到这一点:

(defun add-to-table (key value)
  (push value (gethash key *ht* nil)))
Run Code Online (Sandbox Code Playgroud)

这将 gethash 和列表访问链视为一个位置,以便推送在这两种情况下都有效。

您可以通过首先确保哈希表条目的存在来明确表达这一点:

(defun add-to-table (key value)
  (unless (nth-value 1 (gethash key *ht*))
    (setf (gethash key *ht*) ()))
  (push value (gethash key *ht*)))
Run Code Online (Sandbox Code Playgroud)

另请参阅ensure-gethash实用alexandria程序库以了解更通用的构造。