我正在尝试编写一个将数据添加到哈希表中的函数。该函数采用一个键和一个值。如果给定的键已存在于表中,则给定的值将附加到与该键关联的现有值中。如果表中尚不存在该键,则将该值放置在列表中并添加到表中。这是实现:
(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是某种指向列表的指针吗?
当您按下 时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程序库以了解更通用的构造。