Skip to content

更新哈希表中的值

哈希表是 Common Lisp 中用于存储键值对的一种基本且高效的数据结构。本教程涵盖了在哈希表中添加、更新和管理条目的标准方法。

在哈希表中添加或更新值的主要机制是 (setf gethash) 的组合。

  • (make-hash-table):创建一个新的空哈希表。
  • (gethash key table):从 table 中检索与 key 关联的值。如果未找到键,则返回 nil。
  • (setf (gethash key table) value):这个强大的构造将与 key 关联的值设置为 value。如果 key 已存在,其值将被更新。如果 key 不存在,则会创建一个新条目。

创建哈希表时,可以使用 :test 参数指定键的比较方式。这对于正确的行为至关重要。

  • #'eql(默认):比较两个对象是否相同。适用于符号和数字。(eql 'a 'a) 为真,但 (eql "a" "a") 为假,因为它们是内存中两个不同的字符串对象。
  • #'equal:比较两个对象是否具有相同的结构和内容。这对于字符串键是必需的。
  • #'eq:类似于 eql,但可能不适用于数字。比较内存位置。
  • #'equalp:equal 的一个更宽松版本,它忽略字符串中的大小写和数字类型。

示例 1:使用默认的 eql 测试(针对符号)

Section titled “示例 1:使用默认的 eql 测试(针对符号)”

本示例展示了使用符号作为键添加和更新哈希表,这与默认的 eql 测试完美配合。

;; 创建一个使用默认测试('eql')的哈希表。
(defvar *symbol-ages* (make-hash-table))
;; 添加初始键值对。
(setf (gethash 'alice *symbol-ages*) 30)
(setf (gethash 'bob *symbol-ages*) 45)
(format t "Initial age of Alice: ~a~%" (gethash 'alice *symbol-ages*))
;; 更新现有值。
(format t "Updating Alice's age to 31...~%")
(setf (gethash 'alice *symbol-ages*) 31)
(format t "Updated age of Alice: ~a~%" (gethash 'alice *symbol-ages*))
;; 添加新条目。
(format t "Adding Charlie, age 25...~%")
(setf (gethash 'charlie *symbol-ages*) 25)
(format t "Age of Charlie: ~a~%" (gethash 'charlie *symbol-ages*))
Initial age of Alice: 30
Updating Alice's age to 31...
Updated age of Alice: 31
Adding Charlie, age 25...
Age of Charlie: 25

示例 2:使用 equal 测试(针对字符串键)

Section titled “示例 2:使用 equal 测试(针对字符串键)”

当使用字符串作为键时,你必须指定 #'equal 作为测试函数。

;; 创建一个使用 'equal' 测试(针对字符串)的哈希表。
(defvar *fruit-prices* (make-hash-table :test #'equal))
;; 添加键值对。
(setf (gethash "apple" *fruit-prices*) 1.50)
(setf (gethash "banana" *fruit-prices*) 0.75)
(format t "Initial price of an apple: $~,2f~%" (gethash "apple" *fruit-prices*))
;; 更新苹果的价格。
(setf (gethash "apple" *fruit-prices*) 1.75)
(format t "Updated price of an apple: $~,2f~%" (gethash "apple" *fruit-prices*))
Initial price of an apple: $1.50
Updated price of an apple: $1.75

要从哈希表中移除一个条目,请使用 remhash 函数。如果移除了条目,它返回 t,否则返回 nil。

(remhash 'bob *symbol-ages*) ; => T(条目已移除)
(gethash 'bob *symbol-ages*) ; => NIL(不再存在)
(remhash 'dave *symbol-ages*) ; => NIL(从未存在)